Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A Method of Worker Thread Pooling

0.00/5 (No votes)
5 Feb 2003 1  
A Method of Worker Thread Pooling

Sample Image - ThreadPool.jpg

Introduction

In many of our applications we use multi threading for better performance. Most of us already knows and using multi threading applications. And we know that thread creation is a resource intensive job. It is always better to reuse the threads, and most of us do this also. This article talks about such a thread pooling (worker thread) architecture. It will be great if you can provide let me know about any bugs that are found and any improvements that can be done to this.

Architecture in brief

The main architecture of the thread pool is given below in the class diagram.

As you can see in the above class diagram the application has mainly three classes, they are

  •  CThPool class : This is the main thread pool class. To use thread pool you have to only create an instance of this class. 
  •  CThread class : This class encapsulates one thread. You don't have to create any instance of this class. The CThPool class will return a CThread class, which you should use. You should not also destroy the CThread object that you received from the CThPool class instance.
  •  CThTarget : This is the base class of all the target objects which can be passed to the CThread class as target. This is an abstract class with run() as the pure virtual method. You should implement the run() in your inherited class. As shown in the class diagram for the class CYourClass.

Using the code

To use the thread pool code we have to do the following 

  • Create an instance of the pool. Refer the sample code below.
    CThpool *m_pThPool;
    m_pThPool = new CThPool();
    
  • Change the maximum pool size if you want to change the maximum number of threads that can be created for use at any instance of time for your system. By default this is 5. You can also change the pool size at run time for better performance as you require. 
    m_pThPool->setMaxPoolSize(10);
        //You can pass any integer value.
    
    
  • Create a class as shown in the class diagram, which will inherit the CThTarget class and implement the pure virtual function void run(). Refer the sample code below
    class CThTargetSuper : public CThTarget  
    {
        public:
            CThTargetSuper();
            virtual ~CThTargetSuper();
            void run();
    }
    
    //------------------------------
    
    void CThTargetSuper::run()
    {
    
        //Write your code here to do some process    
    
    }
  •  Create an instance of your class, which you have defined as above
    CThTargetSuper* pTarget = new CThTargetSuper();
  • When you need to use a thread to do some process which is defined on the run() function of your class. Then get an instance of CThread class from the pool by calling the function getThread(). Then call the setTarget() function of the CThread instance you received and pass the reference of your inherited CThTarget class.
    CThread * pTh=NULL;
    pTh = m_pThPool->getThread();
        //m_pThPool is an instance of CThPool
    
    
    if( pTh!=NULL)
       pTh->setTarget(pTarget);
    

    Note : As you see in the above code the CThread instance received from the CThPool::getThread() function may return NULL. This is in case of all the threads are busy and no free thread is available and the pool's current size is already achieved the Max pool size. If you want the job should be processed then you can try again after some time. The code can be modified as follows. But if this code is executed by the main GUI thread then the while loop may cause problem if the threads are busy for long time. In such cases this code should be executed in a different thread.

    CThread * pTh=NULL; 
    pTh = m_pThPool->getThread();  
        //m_pThPool is an instance of CThPool 
    
    
    while(pTh ==NULL) 
    { 
        Sleep(100); 
        pTh = m_pThPool->getThread();           
    } 
    if( pTh!=NULL) 
       pTh->setTarget(pTarget);
  • After CThread::setTarget() function call the run() function of the CThTarget type object will run in a separate thread. The thread will automatically return to the pool when the run() function finishes. 

    Note : Once the thread will be completed the CThTarget object cannot be used again. This is because once the run() function finishes the thread deletes the instance of the CThTarget. If you want to use the CThTarget object later then you have to tell the thread explicitly by setting the auto delete flag of CThTarget to FALSE as given in the code below.

    CThTargetSuper* pTarget = new CThTargetSuper();
    pTarget->setAutoDelete(FALSE);

    The default value is TURE. You can check this at any time by calling AutoDelete(). It returns TRUE if the flag is set as TRUE.

    Never call setTarget() again on the same CThread instance that you received from the last getThread() object. Always use getThread() on CThPool instance to get a CThread object and then use setTarget() on that object only once.

Additional Features

How To Set Max Free Pool Size

Some times our application may need let 100 threads but most of the time the required thread is less than 20. In that case it is no need to create and keep 100 threads always in the pool. In such cases we can define the maximum free pool size to 20.This will make sure that not more than 20 idle threads will be available in the free pool. If required more number of threads will be created as on demand. Sample code is given below.  

m_pThPool = new CThPool();
m_pThPool->setMaxPoolSize(100);          //Maximum pool size        

m_pThPool->setMaxFreePoolSize(20);       //Maximum free pool size

Getting Statistics

Some times we may require statistics to know at any instance of time how many threads are busy and how many threads are free, what is the pool size now, etc. etc. We can get such information by calling some methods of pool. In the sample application the statistics are also used. The functions that are available to get the statistical information are  

int CThPool::getCurPoolSize()      // returns the current pool size.

int CThPool::getMaxPoolSize()      // returns the maximum pool size.        

int CThPool::getMaxFreePoolSize()  // returns the maximum free pool size.

int CThPool::getFreePoolSize()     // returns the number 

                                   // of idle threads in the pool.

About The Demo Program 

The demo program uses one thread pool. Initially the pool has started with one thread. And the Max pool size is 5. And the maximum free thread size is 2. In the demo program CThTargetSuper is the class, which extends CThTarget and implement the run() method. The run method simply increments the progress bar after sleeping 100 ms till it reaches the end. If more number of threads will be assigned then the progress bar will move fast. The run() methods ends when the progress bar reaches the end of the bar. And the after that the instance of the CThTargetSuper gets deleted by the thread (As the Auto Delete flag is TRUE by default) and the threads returns to the free pool and remains in suspended mode till another work get assigned. The thread may also exit if the number of threads that are present in the free pool is more than the maximum limit.

Executing the Demo Program

After you start the program first create the pool by clicking the CreatePool button. Then you can click on the AssignThread button to assign a new thread. You can not assign more threads than the Max Pool size. The current number of threads busy in the pool is displayed in the statistics along with the idle threads and max pool size. You can change the the maximum pool size by clicking the button "+" or "-" . (Upper limit is defined as 20). You can also change the maximum free pool size by clicking the corresponding "+" / "-" button. You can also press the Refresh button to refresh the statistics. The statistics also gets automatically updated around every 2 seconds.

To repeat the process click on the Reset button so that the progress bar will be reset to initial position. And you can assign the threads again to increase the progress bar's progress.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here