In this tutorial, we're going to extend Tutorial 6 to add a third concurrency strategy: thread-pool. Like Tutorial 6 did to Tutorial 5, we're going to keep the existing strategies that we've already created and add this one in as a "bonus". As you'll see, our basic objects will change but not by a whole lot. To accomplish this, we'll introduce one new major object that helps to abstract the thread pool concept.
Some folks have noted that this tutorial is a bit confusing if you don't first know about ACE_Task. My advice is to give it all a good read a couple of times. If you're still having problems, take a look at the ACE_Task tests in $ACE_ROOT/tests or examples in $ACE_ROOT/examples.
ACE_Task follows the Active Object pattern and executes the methods on the task object in a new thread of execution, i.e it decouples the execution of a method from its invocation. An ACE_Task has an underlying thread (or pool of threads) and a Message_Queue which is the only means of communication among tasks. A Message_Queue consists of Message_Blocks.
The Client_Acceptor is registered with the reactor waiting for connection requests. On some activity, the reactor calls the handle_input() method on the Acceptor. The Client_Handler of the Acceptor (for the thread-pool strategy) unregisters itself from the reactor and enqueues itself in the Message_Queue of the thread-pool waiting for svc() to call handle_input() on it. It would then process the data in its new thread of execution. The ACE_MT_SYNCH option facilitates access of the Mesage_Blocks across different Message_Queues (here from the main thread to the one in the thread pool).
The thread_pool class derives from the ACE_Task class. Its svc() method dequeues the threads in the Message_Queue and calls handle_input() on them. The idle threads can take work from the queue while the other threads are working. It also uses ACE_Atomic_Op as a counter for active threads in the pool. Also, the ACE_Guard class has been used to provide thread-safe counter-incrementation and destruction of the Message_Blocks of the thread-pool. This class guards the critical section region by acquiring the mutex lock on creation and releasing it as soon as it goes out of scope.
Note: a sleep period before all the threads in the pool exit is necessary for complete destruction of the thread pool.
This tutorial gives us a flavour of implementing a server with a thread-pool strategy and how it can be managed using the ACE_Task class, which provides an OO approach to thread-creation and implementation.