Author: James CE Johnson
Description: A first step towards using ACE productively

ACE Tutorial 007
Creating a thread-pool server

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.

Kirthika's Abstract:

In this multithreaded server, the Client_Acceptor has the additional strategy of managing a thread pool. This helps when two clients don't want to share the same resources or when different clients need to run in different priority threads. We could then pool all the same priority clients into one thread-pool. The thread_pool class is a new addition used to implement this strategy. It inherits from ACE_Task with ACE_MT_SYNCH parameter which takes care of syncronization issues amongst multiple threads.

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.

* The additions to this tutorial make use of ACE_Message_Queue which is discussed in depth in Tutorial 10. Feel free to read ahead if you get lost in the message queue stuff.

[Tutorial Index] [Continue This Tutorial]