[并发并行]_[pthread]_[线程池的简单设计与实现]


1.当需要下载网络文件时,无限制的new 一个新线程来下载时,必然会造成创建销毁线程时的资源消耗。还有就是处理一些网络通信时,如果无限制的开线程,势必会造成系统资源严重浪费。这时候线程池能很好的解决线程复用的问题。

2.这里花了5小时做了一个简单的线程池实现,目的是给童鞋做个参考,满足特定任务的线程池也不是非常难的技术。

3.示例程序开了一个容量是5个线程的线程池下载文件,启动了10次下载任务。还有就是多线程的调试其实挺麻烦,怪不得那么多语言Scala,Erlang实现了自己的并发模型。

4.有错误的地方请指出。

5.还有其他更完善的线程池实现,如基于boost的,http://sourceforge.net/projects/threadpool/?source=directory. 只不过我习惯于能不用第3方库代码就不用的原则,原因就是引入第3方库就是引入了依赖和潜在的很难调试的Bug.不解释。

6.使用pthread线程库实现线程池, curl 做下载的例子. 这个线程池性能不算高, 但是基本能满足要求, 动态添加任务, 并发执行, 线程重用.


2016.8.25 修正线程池任务执行完后Sleep的不适宜.


文件1.2 

bas_thread_pool.h,bas_thread_pool.cpp

/*
 * 
  *
   *  Created on: 2013-3-13
    *  Author: Sai
	 */

#ifndef BAS_THREAD_POOL_H_
#define BAS_THREAD_POOL_H_

#include <vector>
#include <queue>
#include "pthread.h"

#include "bas_thread_task.h"

class BASThread;

//1.暂时不能动态设置线程个数.
class BASThreadPool
{
public:
	BASThreadPool(size_t max_thread_number);
	~BASThreadPool();
	void AddAsynTask(TaskFunc task_func, void* userdata);
	void Activate(); //1.激活线程池.启动扫描线程.
	void Destroy(); //1.销毁线程池,必然要结束掉所有的线程,等待线程结束.
	void WaitTaskFinishAndDestroy();

	inline void SetWaitTime(unsigned milliseconds)
	{
		wait_time_ = milliseconds;
	}
	inline unsigned GetWaitTime()
	{
		return wait_time_;
	}
	inline size_t GetMaxThreadNumber()
	{
		return max_thread_number_;
	}

	void Execute(size_t *queue_remain_number,size_t *free_thread_number);

	void AddFreeThreadToQueue(BASThread* thread);
	bool is_destroy_; //1.通知销毁线程.
	bool is_wait_and_destroy_;

	int GetQueueTaskCount();
	void WaitQueueTaskSignal();

private:
	static void* ScanTask(void* userdata);

	void SignalTaskQueue();
	void LockTaskQueue();
	void UnlockTaskQueue();

	void LockFreeThreadQueue();
	void UnlockFreeThreadQueue();

	size_t max_thread_number_; //1.最大正在执行的线程数.
	unsigned wait_time_;

	std::vector<BASThread*> threads_; //1.线程池容器
	std::queue<BASThread*> free_thread_que_; //1.空闲线程队列
	pthread_mutex_t free_thread_que_mutex_; //1.线程池队列互斥量

	std::queue<BASThreadTask*> task_que_; //1.任务队列
	pthread_mutex_t task_que_mutex_; //1.线程池队列互斥量
	pthread_cond_t task_que_cond_; // 1.线程池队列信号
	pthread_t task_que_thread_; //1.队列扫描线程,判断线程池里有没有未完成的任务。

};

#endif /* DH_THREAD_POOL_H_ */




/*
 * 
  *
   *  Created on: 2013-3-13
    *  Author: Sai
	 */

#include "bas_thread_pool.h"

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

BASThreadPool::BASThreadPool(size_t max_thread_number)
{
	max_thread_number_ = max_thread_number;
	is_destroy_ = false;
	is_wait_and_destroy_ = false;
	task_que_mutex_ = NULL;
	free_thread_que_mutex_ = NULL;
	wait_time_ = 500;

	pthread_mutex_init(&task_que_mutex_, NULL);
	pthread_cond_init(&task_que_cond_,NULL);

	pthread_mutex_init(&free_thread_que_mutex_, NULL);

}

BASThreadPool::~BASThreadPool()
{
	cout << "~BASThreadPool: " << endl;
	pthread_mutex_destroy(&task_que_mutex_);
	pthread_cond_destroy(&task_que_cond_);

	pthread_mutex_destroy(&free_thread_que_mutex_);
}

void BASThreadPool::LockFreeThreadQueue()
{
	pthread_mutex_lock(&free_thread_que_mutex_);
}

void BASThreadPool::UnlockFreeThreadQueue()
{
	pthread_mutex_unlock(&free_thread_que_mutex_);
}

void BASThreadPool::LockTaskQueue()
{
	pthread_mutex_lock(&task_que_mutex_);
}

void BASThreadPool::UnlockTaskQueue()
{
	pthread_mutex_unlock(&task_que_mutex_);
}

void BASThreadPool::AddFreeThreadToQueue(BASThread* thread)
{
	//1.等待下一个任务.
	LockFreeThreadQueue();
	free_thread_que_.push(thread);
	UnlockFreeThreadQueue();
}

void BASThreadPool::Execute(size_t *queue_remain_number,
	size_t *free_thread_number)
{
	//cout << "BASThreadPool::Execute  begin" << endl;
	LockFreeThreadQueue();
	//1.获取空闲线程数,并且队列里还有未执行的任务.
	//2.弹出任务.执行任务.
	if (!free_thread_que_.empty())
	{
		LockTaskQueue();
		if (!task_que_.empty())
		{
			BASThreadTask* task = task_que_.front();
			task_que_.pop();

			//1.设置任务.
			BASThread* free_thread = free_thread_que_.front();
			free_thread_que_.pop();
			free_thread->task_ = task;
			//2.通知空闲线程启动.
			free_thread->Notify();

			*queue_remain_number = task_que_.size();
		}
		else
		{
			*queue_remain_number = 0;
		}
		UnlockTaskQueue();

		*free_thread_number = free_thread_que_.size();
	}
	else
	{
		*free_thread_number = 0;
	}
	UnlockFreeThreadQueue();
}

void* BASThreadPool::ScanTask(void* userdata)
{
	BASThreadPool* pool = (BASThreadPool*) userdata;
	size_t queue_number = 0;
	size_t free_thread_number = 0;
	while (true)
	{
		if (pool->is_destroy_)
		{
			break;
		}
		pool->Execute(&queue_number, &free_thread_number);

		if (pool->is_wait_and_destroy_ && !queue_number
			&& free_thread_number == pool->GetMaxThreadNumber())
		{
			pool->is_destroy_ = true;
			break;
		}

		if(queue_number)
		{
			if(free_thread_number) continue;
			else
			{
				// 无空闲线程
				Sleep(pool->GetWaitTime());
			}
		}else
		{
			// 进入等待
			pool->LockTaskQueue();
			if(!pool->GetQueueTaskCount())
			{
				pool->WaitQueueTaskSignal();
			}
			pool->UnlockTaskQueue();
		}
	}

	cout << "BASThreadPool::ScanTask end" << endl;
	return NULL;
}

void BASThreadPool::WaitQueueTaskSignal()
{
	pthread_cond_wait(&task_que_cond_,&task_que_mutex_);
}

int BASThreadPool::GetQueueTaskCount()
{
	return task_que_.size();
}

void BASThreadPool::Activate()
{
	//1.暂时先直接创建线程.
	for (int i = 0; i < max_thread_number_; ++i)
	{
		BASThread* thread = new BASThread(this);
		threads_.push_back(thread);
		thread->Start();
	}

	//1.启动扫描线程.
	pthread_create(&task_que_thread_, NULL, &ScanTask, this);
}

void BASThreadPool::WaitTaskFinishAndDestroy()
{
	is_wait_and_destroy_ = true;
	pthread_join(task_que_thread_, NULL);

	//1.再停止工作线程.
	size_t size = threads_.size();
	for (size_t i = 0; i < size; ++i)
	{
		BASThread* thread = threads_[i];
		thread->Destroy();
		cout << "thread->Destroy()" << endl;
		delete thread;
	}
}

void BASThreadPool::Destroy()
{
	//1.等待全部线程结束.
	cout << "BASThreadPool::Destroy begin" << endl;

	//1.先停止扫秒线程
	is_destroy_ = true;
	pthread_join(task_que_thread_, NULL);

	//1.再停止工作线程.
	size_t size = threads_.size();
	for (size_t i = 0; i < size; ++i)
	{
		BASThread* thread = threads_[i];
		thread->Destroy();
		cout << "thread->Destroy()" << endl;
		delete thread;
	}

	size_t remain = task_que_.size();
	for (size_t i = 0; i < remain; ++i)
	{
		BASThreadTask* task = task_que_.front();
		task_que_.pop();
		delete task;
	}

	cout << "BASThreadPool::Destroy end " << endl;
}

void BASThreadPool::SignalTaskQueue()
{
	pthread_cond_signal(&task_que_cond_);
}

void BASThreadPool::AddAsynTask(TaskFunc task_func, void* userdata)
{
	BASThreadTask *task = new BASThreadTask(task_func, userdata);

	LockTaskQueue();
	//1.添加任务到队列.
	task_que_.push(task);
	SignalTaskQueue();
	UnlockTaskQueue();
}




文件3,4 

bas_thread.h, bas_thread.cpp

/*
 * 
 *
 *  Created on: 2013-3-13
 *  Author: Sai
 */

#ifndef BAS_THREAD_H_
#define BAS_THREAD_H_

#include "pthread.h"
#include "bas_thread_task.h"

class BASThreadPool;

//1.代表一个线程的执行对象.不是代表一个线程.
class BASThread
{
public:
	BASThread(BASThreadPool* pool);
	~BASThread();

	BASThreadTask* task_;
	void AddToFreeThreadQueue();
	void Notify();

	void Lock();
	void Unlock();
	void Wait();
	void Join();
	int GetId();
	void Destroy();

	void Start();

private:
	pthread_mutex_t mutex_;
	pthread_cond_t cond_;

	bool is_destroy_;
	pthread_t thread_;
	BASThreadPool* pool_; //1.所属线程池
	static void* DoTask(void* userdata);

	int thread_id_;
};

#endif /* DH_THREAD_H_ */

/*
 * bas_thread.cpp
 *
 *  Created on: 2013-3-13
 *  Author: Sai
 */

#include "bas_thread.h"

#include <stdio.h>
#include <iostream>

#include "bas_thread_pool.h"

using namespace std;

BASThread::BASThread(BASThreadPool* pool)
{
	task_ = NULL;
	is_destroy_ = false;
	mutex_ = NULL;
	cond_ = NULL;
	pool_ = pool;
	thread_id_ = 0;

	pthread_mutex_init(&mutex_, NULL);
	pthread_cond_init(&cond_, NULL);
}

void BASThread::Start()
{
	pthread_create(&thread_, NULL, &BASThread::DoTask, this);
	thread_id_ = (int)thread_.p;
}

BASThread::~BASThread()
{
	pthread_mutex_destroy(&mutex_);
	pthread_cond_destroy(&cond_);
}

void BASThread::Lock()
{
	pthread_mutex_lock(&mutex_);
}

void BASThread::Unlock()
{
	pthread_mutex_unlock(&mutex_);
}

void BASThread::AddToFreeThreadQueue()
{
	pool_->AddFreeThreadToQueue(this);
}

void BASThread::Wait()
{
	pthread_cond_wait(&cond_, &mutex_);
}

void BASThread::Join()
{
	int res = pthread_join(thread_, NULL);
	cout << "res:  " << res << endl;

}

void BASThread::Destroy()
{
	Lock();
	is_destroy_ = true;
	Notify();
	Unlock();
	Join();
}

int BASThread::GetId()
{
	return thread_id_;
}

void* BASThread::DoTask(void* userdata)
{
	BASThread* thread = (BASThread*) userdata;
	while (true)
	{
		thread->Lock();
		if (thread->is_destroy_)
		{
			thread->Unlock();
			break;
		}
		thread->Unlock();

		BASThreadTask* task = thread->task_;
		if (task)
		{
			(*task->task_func_)(task->userdata_);
			cout << "task finish: " << thread->GetId() << endl;
			delete task;
			thread->task_ = NULL;
		}

		//1.通知队列加入空闲线程.
		//2.挂起线程.
		//1.如果是需要销毁,不需要进入等待.
		thread->Lock();
		if (thread->is_destroy_)
		{
			thread->Unlock();
			break;
		}
		thread->AddToFreeThreadQueue();
		thread->Wait();
		thread->Unlock();
	}

	cout << "thread finish: " << thread->GetId() << endl;
	return NULL;
}

void BASThread::Notify()
{
	pthread_cond_signal(&cond_);
}



文件5

bas_thread_task.h

/*
 * bas_thread_task.h
 *
 *  Created on: 2013-3-13
 *  Author: Sai
 */

#ifndef BAS_THREAD_TASK_H_
#define BAS_THREAD_TASK_H_

typedef void * (*TaskFunc)(void * arg);

class BASThreadTask
{
public:
	BASThreadTask(TaskFunc task_func, void* userdata)
	{
		userdata_ = userdata;
		task_func_ = task_func;
	}
	~BASThreadTask()
	{
	}
	void* userdata_;
	TaskFunc task_func_;
};

#endif /* DH_THREAD_TASK_H_ */




文件6,7

dh_download_manager.h,dh_download_manager.cpp

/*
 * dh_download_manager.h
 *
 *  Created on: 2013-3-13
 *  Author: Sai
 */

#ifndef DH_DOWNLOAD_MANAGER_H_
#define DH_DOWNLOAD_MANAGER_H_

#include <stdlib.h>

typedef size_t (*WriteMemoryCallback)(void *contents, size_t size, size_t nmemb,
		void *userp);

class DhDownloadManager
{
public:
	DhDownloadManager();
	~DhDownloadManager();
	int Process(const char* url, WriteMemoryCallback callback_func,
			void* userdata);
};

#endif /* DH_DOWNLOAD_MANAGER_H_ */

/*
 * dh_download_manager.cpp
 *
 *  Created on: 2013-3-13
 *  Author: Sai
 */

#include "dh_download_manager.h"

#include <stdlib.h>
#include "curl/curl.h"

DhDownloadManager::DhDownloadManager()
{
	curl_global_init (CURL_GLOBAL_ALL);
}

DhDownloadManager::~DhDownloadManager()
{
	curl_global_cleanup();
}

int DhDownloadManager::Process(const char* url,
		WriteMemoryCallback callback_func, void* userdata)
{
	CURL *curl_handle = curl_easy_init();

	curl_easy_setopt(curl_handle, CURLOPT_URL, url);
	curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, callback_func);
	curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, userdata);
	curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "test-agent/1.0");
//	curl_easy_setopt(curl_handle, CURLOPT_PROXY, "192.168.0.1:808");
//	curl_easy_setopt(curl_handle, CURLOPT_HTTPPROXYTUNNEL, 1L);
	int ret = curl_easy_perform(curl_handle);

	curl_easy_cleanup(curl_handle);
	return 0;
}


文件8:

main.cpp

/*
 * main.cpp
 *
 *  Created on: 2013-3-13
 *  Author: Sai
 */

#include <stdio.h>
#include <string.h>
#include <iostream>

using namespace std;

#include "dh_thread_pool.h"
#include "dh_thread_task.h"

#include "dh_download_manager.h"

typedef struct DiskData
{
	FILE* file;
}DiskData;

size_t WriteToDisk(void *contents, size_t size, size_t nmemb,
		void *userp)
{
	DiskData* dd = (DiskData*) userp;
	size_t number = nmemb*size;
	size_t writed_num = fwrite(contents,1,number,dd->file);
	return writed_num;
}

void *RunTaskFunc(void * arg)
{
	int* i = (int*) arg;
	cout << "thread index: " << *i << endl;
	DhDownloadManager* manager = new DhDownloadManager();
	static const char* url =
			"http://www.istonsoft.com/downloads/iston-video-converter.exe";

	DiskData dd;
	char path[8];
	memset(path,0,sizeof(path));
	sprintf(path,"%d.exe",*i);
	dd.file = fopen(path,"wb");
	manager->Process(url,&WriteToDisk,&dd);

	fclose(dd.file);
	return NULL;
}

int main(int argc, char *argv[])
{
	setbuf(stdout, (char*) NULL);
	setbuf(stderr, (char*) NULL);
	printf("Hello, world\n");
	DhThreadPool *pool = new DhThreadPool(5);
	pool->Activate();

	for (int o = 0; o < 10; ++o)
	{
		int *i = new int;
		*i = o;
		pool->AddAsynTask(&RunTaskFunc, i);
	}

	getchar();

	pool->Destroy();
	delete pool;

	return 0;
}



提示:完整项目文件下载地址: http://download.csdn.net/detail/infoworld/5138920




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Peter(阿斯拉达)

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

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

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

打赏作者

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

抵扣说明:

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

余额充值