C++11实现线程池

什么是线程池

线程池(thread pool)是一种线程使用模式。线程过多或者频繁创建和销毁线程会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着管理器分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价,以及保证了线程的可复用性。线程池不仅能够保证内核的充分利用,还能防止过分调度。

线程池原理

预先创建预定数量的线程,将多个任务加入到任务队列。类似于生产者消费者,多个线程相当于消费者,一个任务队列充当生产者。当任务队列被塞入任务时,线程们就去竞争这些任务,但每次只有一个线程能够得到任务,该任务执行完成后,线程可以释放出来去承接下一个任务,这样保证多个任务可以并发地执行。

线程池的原理如图所示
在这里插入图片描述
一个任务队列有n个任务,可以通过线程池的调度分配到m个线程上去并发执行

线程池实现

机遇C++11 的线程库编写
thread_pool.hpp

#ifndef _THREAD_POOL_H_
#define _THREAD_POOL_H_

#include <thread>
#include <mutex>
#include <atomic>
#include <condition_variable>
#include <functional>
#include <vector>
#include <queue>

class ThreadPool
{
public:
	using Task = std::function<void()>;

	explicit ThreadPool(int num): _thread_num(num), _is_running(false)
	{}

	~ThreadPool()
	{
		if (_is_running)
			stop();
	}

	void start()
	{
		_is_running = true;

		// start threads
		for (int i = 0; i < _thread_num; i++)
			_threads.emplace_back(std::thread(&ThreadPool::work, this));
	}

	void stop()
	{
		{
			// stop thread pool, should notify all threads to wake
			std::unique_lock<std::mutex> lk(_mtx);
			_is_running = false;
			_cond.notify_all(); // must do this to avoid thread block
		}

		// terminate every thread job
		for (std::thread& t : _threads)
		{
			if (t.joinable())
				t.join();
		}
	}

	void appendTask(const Task& task)
	{
		if (_is_running)
		{
			std::unique_lock<std::mutex> lk(_mtx);
			_tasks.push(task);
			_cond.notify_one(); // wake a thread to to the task
		}
	}

private:
	void work()
	{
		printf("begin work thread: %d\n", std::this_thread::get_id());

		// every thread will compete to pick up task from the queue to do the task
		while (_is_running)
		{
			Task task;
			{
				std::unique_lock<std::mutex> lk(_mtx);
				if (!_tasks.empty())
				{
					// if tasks not empty, 
					// must finish the task whether thread pool is running or not
					task = _tasks.front();
					_tasks.pop(); // remove the task
				}
				else if (_is_running && _tasks.empty())
					_cond.wait(lk);
			}

			if (task)
				task(); // do the task
		}

		printf("end work thread: %d\n", std::this_thread::get_id());
	}

public:
	// disable copy and assign construct
	ThreadPool(const ThreadPool&) = delete;
	ThreadPool& operator=(const ThreadPool& other) = delete;

private:
	std::atomic_bool _is_running; // thread pool manager status
	std::mutex _mtx;
	std::condition_variable _cond;
	int _thread_num;
	std::vector<std::thread> _threads;
	std::queue<Task> _tasks;
};


#endif // !_THREAD_POOL_H_

main.cpp

#include <iostream>
#include <chrono>
#include "thread_pool.hpp"

void fun1()
{
	std::cout << "working in thread " << std::this_thread::get_id() << std::endl;
}

void fun2(int x)
{
	std::cout << "task " << x << " working in thread " << std::this_thread::get_id() << std::endl;
}

int main(int argc, char* argv[])
{
	ThreadPool thread_pool(3);
	thread_pool.start();
	std::this_thread::sleep_for(std::chrono::milliseconds(500));

	for (int i = 0; i < 6; i++)
	{
		//thread_pool.appendTask(fun1);
		thread_pool.appendTask(std::bind(fun2, i));
		std::this_thread::sleep_for(std::chrono::milliseconds(500));
	}

	thread_pool.stop();

	getchar();
	return 0;
}

执行结果

begin work thread: 10492
begin work thread: 15024
begin work thread: 11684
task 0 working in thread 10492
task 1 working in thread 15024
task 2 working in thread 11684
task 3 working in thread 10492
task 4 working in thread 15024
task 5 working in thread 11684
end work thread: 11684
end work thread: 10492
end work thread: 15024
  • 任务调度需要加锁和互斥
  • 每次添加一个新的任务就唤醒一个线程
  • 线程池析构时限唤醒所有线程,然后终止线程回收资源
  • 没有实现线程的优先级调度
  • 5
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值