用C++实现简单线程池

线程池

什么是线程池

  • 在使用线程的CS模型中,服务器端每接收到一个客户端请求,都会为客户端创建线程资源,当有大量突发性请求时,服务器来不及为每个客户端创建线程。线程每次的创建与销毁都会耗费服务器大量资源与时间,可以在服务器一开始就创建好一堆线程,等到客户端请求来临直接让这些线程进行处理,这就是线程池。
  • 线程池是一种多线程的处理模式,在线程池启动之后,向线程池中添加任务,线程池中的线程将会自动处理这些任务

适用场景

  • 需要大量的线程来完成任务,并且每个任务的时间比较短。在WEB服务器上适用线程池是非常有必要的,单个任务量小,任务量大。
  • 对性能比较苛刻,需要立即做出应答。
  • 接收突发性的大量请求,但是服务器不至于产生大量线程。

简单实现

任务模块:适用setData为每个对象设置任务,使用Run来执行任务队列。

struct Task{
	public:
		void *_data;
	public:
		bool setData(void *data){
			_data = data;
		}

		bool Run(){
			srand(time(NULL));
			int sec = rand() % 3;
			printf("id:%p -- run data -- %s -- sleep:%d\n", pthread_self(), _data, sec);
			sleep(sec);
		}
};

线程池模块

class pthreadPool{
	private:
		int _max_thr; //max pthread
		int _cur_thr; //now pthread
		bool _stop_flag; //is stop
		std::queue<Task*> _queue;
		int _cap; //queue capacity
		pthread_mutex_t _lock;
		pthread_cond_t _full;
		pthread_cond_t _empty;
};
  • 使用STL中的队列来模拟实现任务队列,_max_thr表示当前线程池中最大的线程数,
  • _cur_thr是当前的线程的数量,_stop_flag是否停止标志,_cap是队列的最大长度。

构造函数:对相关互斥锁和条件变量进行初始化

pthreadPool(int max_thr = 5, int max_queue = 10)
			: _max_thr(max_thr)
			, _cur_thr(0)
			, _stop_flag(false)
			, _cap(max_queue)
		{
			pthread_mutex_init(&_lock, NULL);
			pthread_cond_init(&_full, NULL);
			pthread_cond_init(&_empty, NULL);
		}

初始化线程池:创建线程池支持的最大个数个线程

bool initPool(){
	pthread_t tid;
	int i, ret;
	for(i = 0; i < _max_thr; i++){
		ret = pthread_create(&tid, NULL, thrStart, (void*)this);
		if(ret != 0){
			std::cerr << "pthread_create error" << std::endl;	
			return false;
		}
		pthread_detach(tid);
	}
}

向线程池中添加任务

bool addTask(Task *task){
	pthread_mutex_lock(&_lock);
	while(queueIsFull()){
		pthread_cond_wait(&_full, &_lock);
	}
	_queue.push(task);
	pthread_cond_signal(&_empty);
	pthread_mutex_unlock(&_lock);
	return true;
}
  • 在每次向线程池中添加任务时,为了防止其他线程获得CPU调度产生的数据安全问题,都需要先对其进行加锁操作
  • 如果任务队列满了就需要等待在_full条件变量上,此处要用while循环来判断,而不能用if
  • 队列不满,向队列中添加任务,添加完毕之后向等待在_empty上的线程做出通知,最后释放锁,添加完毕

线程处理函数

static void *thrStart(void *arg){
	pthreadPool *pool = (pthreadPool*)arg;
	while(1){
		pthread_mutex_lock(&pool->_lock);
		//queue is empty, wait
		while(pool->queueIsEmpty() && !(pool->_stop_flag)){
			pthread_cond_wait(&pool->_empty, &pool->_lock);
		}
		
		if(pool->queueIsEmpty() && pool->_stop_flag){
			std::cout << "-pthread eixt-" << std::endl;
			pool->_cur_thr--;
			pthread_mutex_unlock(&pool->_lock);
			pthread_cond_signal(&pool->_full);
			pthread_exit(NULL);
		}
		
		Task* task;
		pool->queuePop(&task);
		pthread_mutex_unlock(&pool->_lock);
		pthread_cond_signal(&pool->_full);
		task->Run();
	}
}
  • 此处线程处理函数声明为静态函数,所以在创建线程时需要把隐含的this指针传递过来
  • 在进行操作之前先进行加锁操作,如果任务队列为空并且不退出状态就等待在_empty
  • 取出任务之后,因为不知道任务具体执行的时间,为了防止死锁,所以先进行解锁操作,通知等待在_full上的线程可以添加任务
  • 最后执行任务。

判断是否停止线程池

bool stop(){
	pthread_mutex_lock(&_lock);
	if(_stop_flag){
		pthread_mutex_unlock(&_lock);
		return false;
	}
	
	_stop_flag = true;
	while(_cur_thr > 0){
		pthread_cond_broadcast(&_empty);
		pthread_cond_wait(&_full, &_lock);
	}
	pthread_mutex_unlock(&_lock);
	return false;
}

猜你喜欢

转载自blog.csdn.net/yikaozhudapao/article/details/85275247
今日推荐