/*
* Copyright 2007-2008 Stephen Liu
* For license terms, see the file COPYING along with this library.
*/
#ifndef __spprocthread_hpp__
#define __spprocthread_hpp__
#include <pthread.h>
typedef struct tagSP_ProcThread SP_ProcThread_t;
class SP_ProcThreadPool {
public:
typedef void ( * DispatchFunc_t )( void * );
SP_ProcThreadPool( int maxThreads, const char * tag = 0 );
~SP_ProcThreadPool();
// set a callback for when all threads are idle
void setFullCallback( DispatchFunc_t fullCallback, void * arg );
/// @return 0 : OK, -1 : cannot create thread
int dispatch( DispatchFunc_t dispatchFunc, void *arg );
void wait4idler();
int getMaxThreads();
private:
char * mTag;
int mMaxThreads;
int mIndex;
int mTotal;
int mIsShutdown;
pthread_mutex_t mMainMutex;
pthread_cond_t mIdleCond;
pthread_cond_t mFullCond;
pthread_cond_t mEmptyCond;
SP_ProcThread_t ** mThreadList;
DispatchFunc_t mFullCallback;
void * mFullCallbackArg;
static void * wrapperFunc( void * );
int saveThread( SP_ProcThread_t * thread );
};
#endif
/*
* Copyright 2007-2008 Stephen Liu
* For license terms, see the file COPYING along with this library.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <syslog.h>
#include "spprocthread.hpp"
typedef struct tagSP_ProcThread {
pthread_t mId;
pthread_mutex_t mMutex;
pthread_cond_t mCond;
SP_ProcThreadPool::DispatchFunc_t mFunc;
void * mArg;
SP_ProcThreadPool * mParent;
} SP_ProcThread_t;
SP_ProcThreadPool :: SP_ProcThreadPool( int maxThreads, const char * tag )
{
if( maxThreads <= 0 ) maxThreads = 2;
pthread_mutex_init( &mMainMutex, NULL );
pthread_cond_init( &mIdleCond, NULL );
pthread_cond_init( &mFullCond, NULL );
pthread_cond_init( &mEmptyCond, NULL );
mMaxThreads = maxThreads;
mIndex = 0;
mIsShutdown = 0;
mTotal = 0;
tag = NULL == tag ? "unknown" : tag;
mTag = strdup( tag );
mThreadList = ( SP_ProcThread_t ** )malloc( sizeof( void * ) * mMaxThreads );
memset( mThreadList, 0, sizeof( void * ) * mMaxThreads );
mFullCallback = NULL;
mFullCallbackArg = NULL;
}
SP_ProcThreadPool :: ~SP_ProcThreadPool()
{
pthread_mutex_lock( &mMainMutex );
if( mIndex < mTotal ) {
syslog( LOG_DEBUG, "[tp@%s] waiting for %d thread(s) to finish\n", mTag, mTotal - mIndex );
pthread_cond_wait( &mFullCond, &mMainMutex );
}
mIsShutdown = 1;
for( int i = 0; i < mIndex; i++ ) {
SP_ProcThread_t * thread = mThreadList[ i ];
pthread_mutex_lock( &thread->mMutex );
pthread_cond_signal( &thread->mCond ) ;
pthread_mutex_unlock ( &thread->mMutex );
}
if( mTotal > 0 ) {
syslog( LOG_DEBUG, "[tp@%s] waiting for %d thread(s) to exit\n", mTag, mTotal );
pthread_cond_wait( &mEmptyCond, &mMainMutex );
}
syslog( LOG_DEBUG, "[tp@%s] destroy %d thread structure(s)\n", mTag, mIndex );
for( int i = 0; i < mIndex; i++ ) {
SP_ProcThread_t * thread = mThreadList[ i ];
pthread_mutex_destroy( &thread->mMutex );
pthread_cond_destroy( &thread->mCond );
free( thread );
mThreadList[ i ] = NULL;
}
pthread_mutex_unlock( &mMainMutex );
mIndex = 0;
pthread_mutex_destroy( &mMainMutex );
pthread_cond_destroy( &mIdleCond );
pthread_cond_destroy( &mFullCond );
pthread_cond_destroy( &mEmptyCond );
free( mThreadList );
mThreadList = NULL;
free( mTag );
mTag = NULL;
}
void SP_ProcThreadPool :: setFullCallback( DispatchFunc_t fullCallback, void * arg )
{
mFullCallback = fullCallback;
mFullCallbackArg = arg;
}
int SP_ProcThreadPool :: getMaxThreads()
{
return mMaxThreads;
}
int SP_ProcThreadPool :: dispatch( DispatchFunc_t dispatchFunc, void *arg )
{
int ret = 0;
pthread_attr_t attr;
SP_ProcThread_t * thread = NULL;
pthread_mutex_lock( &mMainMutex );
if( mIndex <= 0 && mTotal >= mMaxThreads ) {
pthread_cond_wait( &mIdleCond, &mMainMutex );
}
if( mIndex <= 0 ) {
SP_ProcThread_t * thread = ( SP_ProcThread_t * )malloc( sizeof( SP_ProcThread_t ) );
thread->mId = 0;
pthread_mutex_init( &thread->mMutex, NULL );
pthread_cond_init( &thread->mCond, NULL );
thread->mFunc = dispatchFunc;
thread->mArg = arg;
thread->mParent = this;
pthread_attr_init( &attr );
pthread_attr_setdetachstate( &attr,PTHREAD_CREATE_DETACHED );
if( 0 == pthread_create( &( thread->mId ), &attr, wrapperFunc, thread ) ) {
mTotal++;
syslog( LOG_DEBUG, "[tp@%s] create thread#%ld\n", mTag, thread->mId );
} else {
ret = -1;
syslog( LOG_WARNING, "[tp@%s] cannot create thread\n", mTag );
pthread_mutex_destroy( &thread->mMutex );
pthread_cond_destroy( &thread->mCond );
free( thread );
}
pthread_attr_destroy( &attr );
} else {
mIndex--;
thread = mThreadList[ mIndex ];
mThreadList[ mIndex ] = NULL;
thread->mFunc = dispatchFunc;
thread->mArg = arg;
thread->mParent = this;
pthread_mutex_lock( &thread->mMutex );
pthread_cond_signal( &thread->mCond ) ;//唤醒空闲线程继续工作
pthread_mutex_unlock ( &thread->mMutex );
}
pthread_mutex_unlock( &mMainMutex );
return ret;
}
void SP_ProcThreadPool :: wait4idler()
{
if( mIndex <= 0 && mTotal >= mMaxThreads ) {
pthread_mutex_lock( &mMainMutex );
if( mIndex <= 0 && mTotal >= mMaxThreads ) {
pthread_cond_wait( &mIdleCond, &mMainMutex );
}
pthread_mutex_unlock( &mMainMutex );
}
}
void * SP_ProcThreadPool :: wrapperFunc( void * arg )
{
SP_ProcThread_t * thread = ( SP_ProcThread_t * )arg;
for( ; 0 == thread->mParent->mIsShutdown; ) {
thread->mFunc( thread->mArg );
pthread_mutex_lock( &thread->mMutex );
if( 0 == thread->mParent->saveThread( thread ) ) {
pthread_cond_wait( &thread->mCond, &thread->mMutex );//工作线程 完成此次工作,进入等待状态,等待主控进程的唤醒
pthread_mutex_unlock( &thread->mMutex );
} else {
pthread_mutex_unlock( &thread->mMutex );
pthread_cond_destroy( &thread->mCond );
pthread_mutex_destroy( &thread->mMutex );
free( thread );
thread = NULL;
break;
}
}
if( NULL != thread ) {
pthread_mutex_lock( &thread->mParent->mMainMutex );
thread->mParent->mTotal--;
if( thread->mParent->mTotal <= 0 ) {
pthread_cond_signal( &thread->mParent->mEmptyCond );
}
pthread_mutex_unlock( &thread->mParent->mMainMutex );
}
return NULL;
}
int SP_ProcThreadPool :: saveThread( SP_ProcThread_t * thread )
{
int ret = -1;
pthread_mutex_lock( &mMainMutex );
if( mIndex < mMaxThreads ) {
mThreadList[ mIndex ] = thread;
mIndex++;
ret = 0;
pthread_cond_signal( &mIdleCond );//通知Master线程 有线程已经空闲下来
if( mIndex >= mTotal ) {
if( NULL != mFullCallback ) mFullCallback( mFullCallbackArg );// 此时如果所有的线程都处于活动状态,则调用此函数。此函数进行扩充
pthread_cond_signal( &mFullCond );// 告诉master线程已满
}
}
pthread_mutex_unlock( &mMainMutex );
return ret;
}
线程池是使用主线程来进行分发,各个工作线程是一个循环不停的工作,当完成一个函数的功能时发出空闲的信号,主线程进行记录。
可以使用两个队列来完成线程池的功能,一个是工作线程队列。一个是空闲线程队列