C++11 线程池简单实现

C++11 线程池简单实现以及测试


话不多说,先上代码

//threadpool.h

#pragma once

#include<vector>
#include<queue>
#include<thread>
#include<iostream>
#include<stdexcept>
#include<condition_variable>
#include<memory>
#include<functional>

const int MAX_THREADS = 1000;

typedef std::function<void(void)> Task;

int num = 0;

class threadPool
{
public:
	threadPool(int number = 1);
	~threadPool();
	bool append(Task task);

private:
	static void* worker(void* arg);
	void run();

private:
	std::vector<std::thread> work_threads;
	std::queue<Task> tasks_queue;

	std::mutex queue_mutex;
	std::condition_variable condition;
	bool stop;

};
threadPool::threadPool(int number) : stop(false)
{
	if (number <= 0 || number > MAX_THREADS) {
		throw std::exception();
	}
	for (int i = 0; i < number; i++) {
		//std::cout << "创建第" << i << "个进程" << std::endl;
		work_threads.emplace_back(threadPool::worker, this);
	}
}

inline threadPool::~threadPool()
{
	{
		std::unique_lock<std::mutex> lock(queue_mutex);
		stop = true;
		condition.notify_all();
		for (auto& ww : work_threads)
			ww.join();
	}
}

bool threadPool::append(Task task)
{
	queue_mutex.lock();
	tasks_queue.push(task);
	queue_mutex.unlock();
	condition.notify_one();
	return true;
}
void* threadPool::worker(void* arg)
{
	threadPool* pool = (threadPool*)arg;
	pool->run();
	return pool;
}

void threadPool::run()
{
	while (!stop) {
		std::unique_lock<std::mutex> lk(this->queue_mutex);
		//queue_mutex.lock();
		this->condition.wait(lk, [this] {return !this->tasks_queue.empty(); });
		if (this->tasks_queue.empty()) {
			continue;
		}
		else {
			Task task = tasks_queue.front();
			tasks_queue.pop();
			lk.unlock();
			//在获取到任务队列的任务之后,应该马上解锁任务队列,再执行这个任务
			task();
		}
	}
}

主要测试task的个数和所开线程数对完成时间的影响。
测试代码中task是计算密集型任务:for循环累加。代码如下:

#include <iostream>
#include"threadpool.h"
#include<Windows.h>
using namespace std;

int show_res = 0;
mutex data_mutex;

class Test
{
public:
	void process_no_static_bind(const int i, const int j) {
		int res = 0;
		for (int n = 0; n < 50000000; n++) {
			res += (i + j);
		}
		//Sleep(500);
		unique_lock<mutex> lk(data_mutex);
		show_res++;
		//cout << show_res << endl;
	}
};

int main() {
	threadPool pool(1);
	int test_num = 100;
	Test tt_bind;

	time_t start, end;
	start = GetTickCount64();
/*	while (true) {
		pool.append(std::bind(&Test::process_no_static_bind, &tt_bind, 3, 4));
	}*/
	cout << "start tag=" << show_res << endl;
	for (int i = 0; i < test_num; i++) {
		pool.append(std::bind(&Test::process_no_static_bind, &tt_bind, i, 4));
		
		//tt_bind.process_no_static_bind(i, 4);
	}
	while (show_res < test_num-1) {
		Sleep(10);
	}
	cout << "end tag=" << show_res << endl;
	end = GetTickCount64();
	cout << "spend time:" << end - start << "mileseconds" << endl;
	exit(0);
}

测试结果说明:

测试一:
执行任务数:10

进程数时间
101203ms
91078ms
81329ms
71250ms
61484ms
51359ms
41765ms
31266ms
21984ms
13547ms

测试二:
在每一个任务中添加一个Sleep(100);
执行任务数:10

进程数时间
101281ms
91265ms
81563ms
71563ms
61547ms
51421ms
41765ms
31578ms
22485ms
14453ms

结合测试一和测试二
有一个猜想:单进程执行完所有任务的时间除以核心数(本次为4)约等于多个线程同时执行任务所需的时间。
所以并不是线程越多,执行的速度越快。
同时还需要考虑到是CPU密集型还是IO密集型
CPU密集型的测试:在任务中执行大量的计算或者循环任务
IO密集型的测试:在任务中使用Sleep()函数阻塞


测试三:
CPU密集型:
执行任务数:10

进程数时间
101156ms
91125ms
81531ms
71453ms
61515ms
51235ms
41703ms
31406ms
22125ms
13641ms

测试四:
IO密集型:
执行任务数:10

进程数时间
10625ms
9640ms
81141ms
71109ms
61140ms
51140ms
41719ms
31719ms
22719ms
14984ms

IO密集型在线程较多的情况下执行速度比CPU密集型要高效
这是因为CPU密集型受制于CPU的核心数,因为任务需要占用的CPU核心数有限,超过核心数的线程不会同时执行
而IO密集型对CPU依赖较小,在一个线程等待IO结果时,其它线程可以继续使用CPU
CPU密集型对CPU依赖较大,在一个线程等待CPU结果时,其它线程不能继续使用CPU
所以对于IO密集型来说,同时使用和任务数相近的线程数可以提高执行速度


测试五:
IO密集型:
执行任务数:100

进程数时间
105062ms
202563ms
501078ms
100641ms
200640ms

由测试五的结果中可以看出,对于IO密集型的任务来说,超过CPU核心数的线程数对于执行速度有较大的提升
因为多线程的使用,使得每个线程在等待IO结果的时间段内CPU可以被其它的线程使用。


测试六:
CPU密集型:
执行任务数:100

进程数时间
105672ms
205766ms
505250ms
1005062ms
2005031ms
48047ms
119172ms

由测试六的结果中可以看出,对于CPU密集型的任务来说,超过CPU核心数的线程数对于执行速度提升不大
可能有的一点速度提升是在多线程时,执行此任务集合的线程数在系统中的比例较大,使的使用CPU的比例也提高
由此造成的其它进程任务使用CPU的时间被挤占,执行50以上线程时,可以明显看到鼠标反应速度下降
而且线程之间的切换也需要消耗时间


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的C语言线程池的代码实现: ```c #include <pthread.h> #include <stdlib.h> #include <stdio.h> #define DEFAULT_THREADS 4 typedef struct { void (*function)(void *); void *argument; } thread_task; typedef struct { thread_task *task_queue; int queue_size; int front; int rear; int count; pthread_mutex_t lock; pthread_cond_t not_empty; pthread_cond_t not_full; int threads_count; pthread_t *threads; int shutdown; } thread_pool; void *thread_pool_function(void *thread_pool_ptr) { thread_pool *pool = (thread_pool *) thread_pool_ptr; thread_task task; while (1) { pthread_mutex_lock(&(pool->lock)); while (pool->count == 0 && !pool->shutdown) { pthread_cond_wait(&(pool->not_empty), &(pool->lock)); } if (pool->shutdown) { pthread_mutex_unlock(&(pool->lock)); pthread_exit(NULL); } task = pool->task_queue[pool->front]; pool->front = (pool->front + 1) % pool->queue_size; pool->count--; if (pool->count == pool->queue_size - 1) { pthread_cond_broadcast(&(pool->not_full)); } pthread_mutex_unlock(&(pool->lock)); (*(task.function))(task.argument); } pthread_exit(NULL); } int thread_pool_create(thread_pool *pool, int threads_count) { int i; pool->threads_count = 0; pool->shutdown = 0; if (threads_count <= 0) { threads_count = DEFAULT_THREADS; } pool->queue_size = threads_count * 2; pool->front = 0; pool->rear = 0; pool->count = 0; pool->task_queue = (thread_task *) malloc(sizeof(thread_task) * pool->queue_size); pool->threads = (pthread_t *) malloc(sizeof(pthread_t) * threads_count); pthread_mutex_init(&(pool->lock), NULL); pthread_cond_init(&(pool->not_empty), NULL); pthread_cond_init(&(pool->not_full), NULL); for (i = 0; i < threads_count; i++) { pthread_create(&(pool->threads[i]), NULL, thread_pool_function, (void *) pool); pool->threads_count++; } return 0; } int thread_pool_add_task(thread_pool *pool, void (*function)(void *), void *argument) { thread_task task; pthread_mutex_lock(&(pool->lock)); while (pool->count == pool->queue_size && !pool->shutdown) { pthread_cond_wait(&(pool->not_full), &(pool->lock)); } if (pool->shutdown) { pthread_mutex_unlock(&(pool->lock)); return -1; } task.function = function; task.argument = argument; pool->task_queue[pool->rear] = task; pool->rear = (pool->rear + 1) % pool->queue_size; pool->count++; if (pool->count == 1) { pthread_cond_broadcast(&(pool->not_empty)); } pthread_mutex_unlock(&(pool->lock)); return 0; } int thread_pool_destroy(thread_pool *pool) { int i; if (pool->shutdown) { return -1; } pool->shutdown = 1; pthread_cond_broadcast(&(pool->not_empty)); pthread_cond_broadcast(&(pool->not_full)); for (i = 0; i < pool->threads_count; i++) { pthread_join(pool->threads[i], NULL); } free(pool->task_queue); free(pool->threads); pthread_mutex_destroy(&(pool->lock)); pthread_cond_destroy(&(pool->not_empty)); pthread_cond_destroy(&(pool->not_full)); return 0; } void task_function(void *argument) { int *value = (int *) argument; printf("Task %d\n", *value); } int main() { int i; int values[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; thread_pool pool; thread_pool_create(&pool, 4); for (i = 0; i < 10; i++) { thread_pool_add_task(&pool, task_function, &values[i]); } thread_pool_destroy(&pool); return 0; } ``` 该实现使用一个循环队列来存储线程任务,线程池的每个线程都会不断地从队列中取出任务并执行。线程池的创建、添加任务和销毁都是线程安全的,确保了多线程环境下线程池的正确性。在本例中,我们创建了一个包含10个任务的线程池,每个任务打印一个数字。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值