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 <list>
#include <cstdio>
#include <exception>
#include <pthread.h>
#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 <exception>
#include <pthread.h>
#include <semaphore.h>

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 <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <errno.h>

#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;

}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
线程池是一种常见的并发编程技术,用于管理和复用线程。它主要用于提高多线程程序的性能和资源利用率,以及控制并发线程的数量。 线程池的作用: 1. 降低线程创建和销毁的开销:线程的创建和销毁是一项开销较高的操作,线程池可以重用已存在的线程,避免频繁地创建和销毁线程,从而减少了开销。 2. 提高系统的并发性能:线程池可以根据系统资源和负载情况自动调整线程数量,合理分配系统资源,提高并发处理能力。 3. 控制并发线程数量:通过设置线程池的参数,可以限制同时执行的任务数量,避免系统资源被过度占用而导致系统崩溃或响应变慢。 线程池实现原理: 1. 线程池管理器:线程池由一个线程池管理器负责创建、初始化和维护线程池。它负责监控线程池中的线程数量、任务队列和线程状态等。 2. 任务队列:线程池通常使用队列来保存待执行的任务。当有新的任务提交到线程池时,先将任务放入任务队列中,然后由空闲的线程从队列中取出任务并执行。 3. 线程池大小:线程池的大小可以根据系统资源和负载情况进行动态调整。一般来说,线程池的大小应根据系统的CPU核心数、内存大小和任务的性质来设定。 4. 线程工厂:线程池使用线程工厂来创建新的线程。线程工厂负责创建线程,并可以设置线程的名称、优先级和其他属性。 5. 拒绝策略:当任务队列已满并且线程池中的线程数量达到上限时,新提交的任务可能会被拒绝执行。这时可以使用一种拒绝策略来处理这些被拒绝的任务,如抛出异常、丢弃任务或等待一段时间再尝试提交等。 总之,线程池通过维护一组可重用的线程和任务队列,提供了一种高效的并发编程方式。它能够优化系统资源的使用,提高程序的性能和可伸缩性,并且可以通过合理配置参数来控制并发线程的数量,从而更好地适应不同的应用场景。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

为了维护世界和平_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值