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的不适宜.
/*
*
*
* 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