linux 线程池原理以及实现

线程池作用

预先创建线程的一种技术,在初始化阶段预先创建一定数量的线程,放入空闲队列中。不消耗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;

}

你可能感兴趣的:(linux,linux,线程池)