预先创建线程的一种技术,在初始化阶段预先创建一定数量的线程,放入空闲队列中。不消耗CPU,只占用较小的内存空间。
任务需要申请线程时,从线程池中申请一个空闲线程,进行处理。
优点: 减少资源创建和销毁的次数,提高系统性能。
缺点:线程过多会带来调用开销,从而影响缓存局部和整体性能。
线程池中可用线程的数量,取决于处理器个数,内核、内存、网络sockets等数量。
需要大量的线程来完成任务,且完成任务的时间比较短
对性能要求高,比如服务端快速相应客户请求;接收大量并发请求
如:web服务器
创建线程: pthread_create()
线程中的等待处理: pthread_cond_wait(),而不使用while(1)
加锁: pthread_mutex_init(), pthread_mutex_lock(),pthread_mutex_unlock()
唤醒线程:pthread_cond_signal(),pthread_cond_broadcast().
队列:队列的作用,存储任务。
扩展:创建管理线程,负责动态创建或销毁线程
C++线程池demo
#ifndef THREADPOOL_H
#define THREADPOOL_H
#include
#include
#include
#include
#include "locker.h"
template< typename T >
class threadpool
{
public:
threadpool( int thread_number = 8, int max_requests = 10000 );
~threadpool();
bool append( T* request );
private:
static void* worker( void* arg );
void run();
private:
int m_thread_number;
int m_max_requests;
pthread_t* m_threads;
std::list< T* > m_workqueue;
locker m_queuelocker;
sem m_queuestat;
bool m_stop;
};
template< typename T >
threadpool< T >::threadpool( int thread_number, int max_requests ) :
m_thread_number( thread_number ), m_max_requests( max_requests ), m_stop( false ), m_threads( NULL )
{
if( ( thread_number <= 0 ) || ( max_requests <= 0 ) )
{
throw std::exception();
}
m_threads = new pthread_t[ m_thread_number ];
if( ! m_threads )
{
throw std::exception();
}
for ( int i = 0; i < thread_number; ++i )
{
printf( "create the %dth thread\n", i );
if( pthread_create( m_threads + i, NULL, worker, this ) != 0 )
{
delete [] m_threads;
throw std::exception();
}
if( pthread_detach( m_threads[i] ) )
{
delete [] m_threads;
throw std::exception();
}
}
}
template< typename T >
threadpool< T >::~threadpool()
{
delete [] m_threads;
m_stop = true;
}
template< typename T >
bool threadpool< T >::append( T* request )
{
m_queuelocker.lock();
if ( m_workqueue.size() > m_max_requests )
{
m_queuelocker.unlock();
return false;
}
m_workqueue.push_back( request );
m_queuelocker.unlock();
m_queuestat.post();
return true;
}
template< typename T >
void* threadpool< T >::worker( void* arg )
{
threadpool* pool = ( threadpool* )arg;
pool->run();
return pool;
}
template< typename T >
void threadpool< T >::run()
{
while ( ! m_stop )
{
m_queuestat.wait();
m_queuelocker.lock();
if ( m_workqueue.empty() )
{
m_queuelocker.unlock();
continue;
}
T* request = m_workqueue.front();
m_workqueue.pop_front();
m_queuelocker.unlock();
if ( ! request )
{
continue;
}
request->process();
}
}
#endif
锁相关函数封装
#ifndef LOCKER_H
#define LOCKER_H
#include
#include
#include
class sem
{
public:
sem()
{
if( sem_init( &m_sem, 0, 0 ) != 0 )
{
throw std::exception();
}
}
~sem()
{
sem_destroy( &m_sem );
}
bool wait()
{
return sem_wait( &m_sem ) == 0;
}
bool post()
{
return sem_post( &m_sem ) == 0;
}
private:
sem_t m_sem;
};
class locker
{
public:
locker()
{
if( pthread_mutex_init( &m_mutex, NULL ) != 0 )
{
throw std::exception();
}
}
~locker()
{
pthread_mutex_destroy( &m_mutex );
}
bool lock()
{
return pthread_mutex_lock( &m_mutex ) == 0;
}
bool unlock()
{
return pthread_mutex_unlock( &m_mutex ) == 0;
}
private:
pthread_mutex_t m_mutex;
};
class cond
{
public:
cond()
{
if( pthread_mutex_init( &m_mutex, NULL ) != 0 )
{
throw std::exception();
}
if ( pthread_cond_init( &m_cond, NULL ) != 0 )
{
pthread_mutex_destroy( &m_mutex );
throw std::exception();
}
}
~cond()
{
pthread_mutex_destroy( &m_mutex );
pthread_cond_destroy( &m_cond );
}
bool wait()
{
int ret = 0;
pthread_mutex_lock( &m_mutex );
ret = pthread_cond_wait( &m_cond, &m_mutex );
pthread_mutex_unlock( &m_mutex );
return ret == 0;
}
bool signal()
{
return pthread_cond_signal( &m_cond ) == 0;
}
private:
pthread_mutex_t m_mutex;
pthread_cond_t m_cond;
};
#endif
C语言线程池demo
#include
#include
#include
#include
#include
#include
#include
#include
#define DEFAULT_TIME 10
#define MIN_WAIT_TASK_NUM 10
#define DEFAULT_THREAD_VARY 10
#define true 1
#define false 0
//task
typedef struct {
void *(*function)(void *);//fun
void *arg;//param
}threadpool_task_t;
typedef struct threadpool
{
pthread_mutex_t lock;//lock
pthread_mutex_t thread_counter;//busy count
pthread_t *threads;//tid
pthread_t *adjust_tid;//manage threadpool
threadpool_task_t *task_queue;//task queue
int queue_front;
int queue_rear;
int queue_size;
int queue_max_size;
pthread_cond_t queue_not_full;
pthread_cond_t queue_not_empty;
int min_thr_num;//
int max_thr_num;
int live_thr_num;
int busy_thr_num;
int wait_exit_thr_num;
int shutdown;//pool status
}threadpool_t;
//void threadpool_thread(void *pthreadpool);
int is_thread_alive(pthread_t tid);
int threadpool_free(threadpool_t *pool);
//manage thread
void *adjust_thread(void *threadpool)
{
int i;
threadpool_t *pool = (threadpool_t *)threadpool;
int queue_size,live_thr_num,busy_thr_num;
while(!pool->shutdown)
{
sleep(10);
pthread_mutex_lock(&(pool->lock));
queue_size = pool->queue_size;
live_thr_num = pool->live_thr_num;
pthread_mutex_unlock(&(pool->lock));
pthread_mutex_lock(&(pool->thread_counter));
busy_thr_num = pool->busy_thr_num;
pthread_mutex_unlock(&(pool->thread_counter));
//create new thread
if(queue_size > MIN_WAIT_TASK_NUM && live_thr_num < pool->max_thr_num)
{
pthread_mutex_lock(&(pool->lock));
int add = 0;
for(i = 0;i < pool->max_thr_num;i++)
{
if(pool->threads[i] == 0 || !is_thread_alive(pool->threads[i]))
{
pthread_create(&(pool->threads[i]),NULL,threadpool,(void *)pool);
add++;
pool->live_thr_num++;
}
}
pthread_mutex_unlock(&(pool->lock));
}
//destory thread
if((busy_thr_num * 2) < live_thr_num && live_thr_num > pool->min_thr_num)
{
pthread_mutex_lock(&(pool->lock));
pool->wait_exit_thr_num = DEFAULT_THREAD_VARY;//destory num
pthread_mutex_unlock(&(pool->lock));
for(i = 0;i<DEFAULT_THREAD_VARY;i++)
pthread_cond_signal(&(pool->queue_not_empty));
}
}
}
//thread
void *threadpool_thread(void *threadpool)
{
threadpool_t *pool = (threadpool_t*)threadpool;
threadpool_task_t task;
while(true)
{
pthread_mutex_lock(&(pool->lock));
//task is 0 wait
while((pool->queue_size == 0) && (!pool->shutdown))
{
pthread_cond_wait(&(pool->queue_not_empty),&(pool->lock));
if(pool->wait_exit_thr_num > 0)
{
pool->wait_exit_thr_num--;
if(pool->live_thr_num > pool->min_thr_num){
printf("thread %x is exiting\n",(unsigned int)pthread_self());
pool->live_thr_num--;
pthread_mutex_unlock(&(pool->lock));
pthread_exit(NULL);
}
}
}
if(pool->shutdown)
{
pthread_mutex_unlock(&(pool->lock));
printf("thread %x is exiting\n",(unsigned int)pthread_self());
pthread_detach(pthread_self());
pthread_exit(NULL);
}
task.function = pool->task_queue[pool->queue_front].function;
task.arg = pool->task_queue[pool->queue_front].arg;
pool->queue_front = (pool->queue_front + 1)%pool->queue_max_size;
pool->queue_size--;
pthread_cond_broadcast(&(pool->queue_not_full));
//task dequeue,exec and free lock
pthread_mutex_unlock(&(pool->lock));
printf("thread %x start working\n",(unsigned int)pthread_self());
pthread_mutex_lock(&(pool->thread_counter));
pool->busy_thr_num++;
pthread_mutex_unlock(&(pool->thread_counter));
(*(task.function))(task.arg);
printf("thread %x end working\n",(unsigned int)pthread_self());
pthread_mutex_lock(&(pool->thread_counter));
pool->busy_thr_num--;
pthread_mutex_unlock(&(pool->thread_counter));
}
pthread_exit(NULL);
}
//add task to thread
int threadpool_add(threadpool_t *pool,void*(*function)(void *args),void *arg)
{
pthread_mutex_lock(&(pool->lock));
while((pool->queue_size == pool->queue_max_size) && (!pool->shutdown))
{
pthread_cond_wait(&(pool->queue_not_full),&(pool->lock));
}
if(pool->shutdown)
{
pthread_cond_broadcast(&(pool->queue_not_empty));
pthread_mutex_unlock(&(pool->lock));
return 0;
}
if(pool->task_queue[pool->queue_rear].arg != NULL)
{
pool->task_queue[pool->queue_rear].arg = NULL;
}
//add task to pool queue
pool->task_queue[pool->queue_rear].function = function;
pool->task_queue[pool->queue_rear].arg = arg;
pool->queue_rear = (pool->queue_rear +1 )%pool->queue_max_size;
pool->queue_size++;
//wakeup
pthread_cond_signal(&(pool->queue_not_empty));
pthread_mutex_unlock(&(pool->lock));
return 0;
}
int threadpool_destory(threadpool_t *pool)
{
int i;
if(pool == NULL)
return -1;
pool->shutdown = true;
pthread_join(*pool->adjust_tid,NULL);
for(i = 0;i<pool->live_thr_num;i++)
pthread_cond_broadcast(&(pool->queue_not_empty));
for(i = 0;i<pool->live_thr_num;i++)
pthread_join(pool->threads[i],NULL);
threadpool_free(pool);
return 0;
}
int threadpool_free(threadpool_t *pool)
{
if(pool == NULL)
return -1;
if(pool->task_queue)
free(pool->task_queue);
if(pool->threads)
{
free(pool->threads);
pthread_mutex_lock(&(pool->lock));
pthread_mutex_destroy(&(pool->lock));
pthread_mutex_lock(&(pool->thread_counter));
pthread_mutex_destroy(&(pool->thread_counter));
pthread_cond_destroy(&(pool->queue_not_empty));
pthread_cond_destroy(&(pool->queue_not_full));
}
free(pool);
pool= NULL;
return 1;
}
int is_thread_alive(pthread_t tid)
{
//send kill signal;retun ESRCH dead
int kill_rc = pthread_kill(tid,0);
if(kill_rc == ESRCH){
return false;
}
return true;
}
void *process(void *arg)
{
printf("thread %x working on task %d\n",(unsigned int )pthread_self(),(int )arg);
sleep(1);
printf("task %d is end\n",(int)arg);
}
threadpool_t *threadpool_create(int min_thr_num,int max_thr_num,int queue_max_size)
{
int i;
threadpool_t *pool=NULL;
do
{
if((pool =( threadpool_t *)malloc(sizeof(threadpool_t)) == NULL)){
printf("malloc threadpool fail\n");
break;
}
pool->min_thr_num = min_thr_num;
pool->max_thr_num = max_thr_num;
pool->busy_thr_num = 0;
pool->live_thr_num = min_thr_num;
pool->wait_exit_thr_num = 0;
pool->queue_size = 0;
pool->queue_max_size = queue_max_size;
pool->queue_front = 0;
pool->queue_rear = 0;
pool->shutdown = false;
//malloc max memory
pool->threads = (pthread_t *)malloc(sizeof(pthread_t) * max_thr_num);
if(pool->threads == NULL)
{
printf("malloc threads fails\n");
break;
}
memset(pool->threads,0,sizeof(pthread_t)*max_thr_num);
//queue memory
pool->task_queue = (threadpool_task_t *)malloc(sizeof(threadpool_task_t)*queue_max_size);
if(pool->task_queue == NULL)
{
printf("malloc task queue fail\n");
break;
}
pthread_mutex_init(&(pool->lock),NULL);
pthread_mutex_init(&(pool->thread_counter),NULL);
pthread_cond_init(&(pool->queue_not_empty),NULL);
pthread_cond_init(&(pool->queue_not_full),NULL);
for(i = 0;i < min_thr_num;i++)
{
pthread_create(&pool->threads[i],NULL,threadpool_thread,(void *)pool);
printf("start thread = %d\n",i);
}
pthread_create(pool->adjust_tid,NULL,adjust_thread,(void*)pool);
return pool;
}while(0);
threadpool_free(pool);
return NULL;
}
int main(void)
{
threadpool_t *thp = threadpool_create(3,100,100);
int num[20],i;
for(i = 0;i<20;i++){
num[i] = i;
threadpool_add(thp,process,(void *)&num[i]);
}
sleep(10);
threadpool_destory(thp);
return 0;
}