Bootstrap

Linux C++ 一个线程池的简单实现(附代码)

这是对 pthread线程的一个简单应用

1.      实现了线程池的概念,线程可以重复使用。

2.      对信号量,互斥锁等进行封装,业务处理函数中只需写和业务相关的代码。

3.      移植性好。如果想把这个线程池代码应用到自己的实现中去,只要写自己的业务处理函数和改写工作队列数据的处理方法就可以了。

 

Sample代码主要包括一个主程序和两个线程实现类

ThreadTest.cpp:主程序

CThreadManager:线程管理 Class,线程池的实现类

CThread:线程 Class.

 

主程序实现方法。

1.      实现 main函数和一个需要线程处理的业务函数(例子代码中业务函数是一个简单的计算函数 Count)。在 main函数中创建 CThreadManager的实例,产生线程池。这个时候,把业务函数作为函数指针传到 CThreadManager里面,最终会被线程调用。

2.      向工作队列中放入业务函数要处理的数据。

3.      设置信号量,唤醒线程。

 

代码
 1   //  线程要执行的函数
 2   int  Count( int  nWork)
 3   {
 4        int  nResult  =  nWork  *  nWork;
 5       printf( " count result is %d\n " ,nResult);
 6  
 7        return   0 ;
 8   }
 9  
10   int  main() {
11  
12        //  创建线程管理类的实例,把要执行的线程函数和最大线程数传进去
13       CThreadManager *  pManager  =   new  CThreadManager(Count,  3 );
14  
15        //  把要进行计算的数放到工作队列中
16       pManager -> PushWorkQue( 5 );
17       pManager -> PushWorkQue( 20 );
18  
19        //  设置信号量,唤醒线程
20       pManager -> PostSem();
21       pManager -> PostSem();
22  
23        //  等待子线程执行
24       sleep( 1 );
25  
26        return   0 ;
27   }

 

CThreadManager实现的方法

1. 把信号量和互斥锁等封装成自己的函数

2. new方法里,循环调用 CThread new方法,启动一定数量(可设定)的线程,产生线程池。

3. 这些线程启动后,就会执行 CThreadManager中的 ManageFuction函数。这个函数是无限循环的,保证了线程在整个程序的生命周期中不销毁。

4. 在循环处理里面,第一行代码就是等待一个信号量,这个信号量是由主程序进行设置的,这个信号信号量如果没有被设置(代表暂时没有需要处理的工作),所有线程都在这里阻塞着。

4.      一旦信号量被设置,根据 Linux线程调度机制,在阻塞的线程队列中,其中一个线程被唤醒,可以执行后面的代码。

5.      从工作队列中取出要进行处理的数据(使用互斥锁进行排他)

6.      通过函数指针调用 main函数传过来的业务函数,处理数据。

7.      业务函数执行完之后,线程进入下一个循环,等待新的信号量。

 

代码
class  CThreadManager {
    friend 
void *  ManageFuction( void * );
private :
    sem_t m_sem;    
//  信号量
    pthread_mutex_t m_mutex;  //  互斥锁

    queue
< int >  m_queWork;  //  工作队列
    list < CThread *>  m_lstThread;  //  线程list

    
int  ( * m_threadFuction)( int );  // 函数指针,指向main函数传过来的线程执行函数
public :
    CThreadManager(
int  ( * threadFuction)( int ),  int  nMaxThreadCnt);
    
virtual   ~ CThreadManager();

    
int  WaitSem();

    
int  PostSem();

    
int  LockMutex();

    
int  UnlockMutex();

    
void  PushWorkQue( int  nWork);

    
int  PopWorkQue();

    
int  RunThreadFunction( int  nWork);
};

//  线程执行函数,它只是个壳子,处理信号量和互斥锁等,
//  最后调用main函数传过来的线程执行函数来实现业务处理
void *  ManageFuction( void *  argv)
{
    CThreadManager
*  pManager  =  (CThreadManager * )argv;

    
//  进行无限循环(意味着线程是不销毁的,重复利用)
     while ( true )
    {
        
//  线程开启后,就在这里阻塞着,直到main函数设置了信号量
        pManager -> WaitSem();
        printf(
" thread wakeup.\n " );

        
//  从工作队列中取出要处理的数
        pManager -> LockMutex();
        
int  nWork  =  pManager -> PopWorkQue();
        pManager
-> UnlockMutex();

        printf(
" call Count function.\n " );
        pManager
-> RunThreadFunction(nWork);
    }
    
return   0 ;
}
//  构造方法
CThreadManager::CThreadManager( int  ( * threadFuction)( int ),  int  nMaxThreadCnt) 
{
    sem_init(
& m_sem,  0 0 );
    pthread_mutex_init(
& m_mutex, NULL);
    m_threadFuction 
=  threadFuction;

    
for ( int  i = 0 ; i < nMaxThreadCnt; i ++ )
    {
        CThread
*  pThread  =   new  CThread(ManageFuction,  this );
        printf(
" thread started.\n " );
        m_lstThread.push_back(pThread);
    }
}

 

CThread实现的方法

CThreadManager比较简单,封装了创建线程和 join线程的函数。

 

代码
CThread::CThread( void *  ( * threadFuction)( void * ), void *  threadArgv) 
{
    
//  初始化线程属性
    pthread_attr_t threadAttr;
    pthread_attr_init(
& threadAttr);

    pthread_create(
& m_thread,  & threadAttr, threadFuction, threadArgv);
}

 

程序的执行结果如下

 

sample代码可以从这里 下载。

代码在windows的eclipse cdt + cygwin 平台上开发, 在Linux平台上测试通过。

;