线程池
来源:互联网 发布:外国人看淘宝 编辑:程序博客网 时间:2024/05/22 01:00
线程池
这几天闲着没事,参考lsd-slam的线程池,做了一个更加泛化的版本,用的c++11的线程库,个人感觉还是比较强大的,拿出来和大家分享一下,代码在git上有托管,这是最新发布的1.2版本:ThreadPool
线程池的使用
这个东西是使用其实比较简单,只需要在项目里面加入ThreadPool.h头文件就可以正常使用,注意编译的时候打开-std=c++11编译flag以及-Wl,–no-as-needed链接flag
只有,你需要做的事情是定义一个ThreadPool的对象,这个对象定义有两个版本
ThreadPool<type> threads(threadNum);ThreadPool<type pointer> threads(threadNum);
即分别是类型版本以及指针类型版本,之后请定义一个 void (*)(void*)
类型的函数,作为工作函数传给线程池,对于每个线程,可以传入不同的函数,这个函数也可以是类的成员函数,但是你需要在传入这个函数指针的同时,传入对象的指针,第三个参数如果类型是对象,那么直接传引用,如果是指针类型,那么请传入相应的指针
threads.reduce(index, workfunc, obj);threads.reduce(index, workfunc, &obj);threads.reduce(index, &someType::workfunc, &someTypeObj, obj);threads.reduce(index, &someType::workfunc, &someTypeObj, &obj);
总共以上4种,注意第一个定义对应的是第一种和第三种,第二个定义对应的是第二种和第四种,那么指针类型定义和类型定义有啥区别呢,我是这么设计的
ThreadPool<type>
这种定义是用来处理对象的,什么意思呢,就是说你可以在外部定义一个结构体,将你函数的输入和输出都放在这个结构体里面,然后分线程进行处理
struct Data { cv::Mat input; cv::Mat *outPut; Data() {} ~Data() {} Data(Data& data) { input = data.input; outPut = data.outPut; } const Data& operator= (Data &data) { input = data.input; //cv::imshow("show", input); outPut = data.outPut; return *this; }};void testOpt(void*data_){ Data* data = (Data*)data_; *(data->outPut) = data->input.clone();}....Data data[4];ThreadPool<Data> thread(4);for(int i = 0; i < 4; ++i) { char buff[32]; memset(buff, 0, 32); sprintf(buff, "data/%d.jpg", i + 1); data[i].input = cv::imread(cv::String(buff)); data[i].outPut = new cv::Mat;} for(int i = 0; i < 4; ++i) { thread.reduce(i, testOpt, data[i]); } while(!thread.isSynchronize());
对于如果是指针,这个设计类似于cuda设计,就是可以对一长串内存分段操作,像这样
const COL = 12;const ROW = 12;void workFunc2(void*data_) { double *data = (double*)data_; for(int i = 0; i < COL; ++i) deal(data[i]);}double data2[ROW][COL];ThreadPool<double*> threads2(ROW);for(int i = 0; i < 12; ++i)threads2.reduce(i, workFunc2, data2[i]);
实现方案
这东西实现起来实际上挺简单的,就没几行代码,一会儿就写完了,主要思路我大概说一下
for(int i = 0; i < maxThreadNum; ++i) { workFunc[i] = defaultFunc<T>; running[i] = false; threads[i] = std::thread(&ThreadPool::workLoop, this, i); }
这段是构造函数里面的,实际上就是把类里面的workLoop函数放到线程里面跑,之后在workLoop里面用condition_variable来对线程进行管理
void workLoop(int idx) { std::unique_lock<std::mutex> lock(Mutex[idx]); while(true) { if(running[idx] == false) conditionVal[idx].wait(lock); workFunc[idx]((void*)&x[idx]); ++sleepThreadNum; workFunc[idx] = defaultFunc<T>; running[idx] = false; } }
简单说就是如果running==false那么线程就等待,否则workFuncidx;调用通过reduce传进来的函数,调用完成之后,将函数设置回默认函数,最后running==false;
bool reduce(int idx, WorkFunc f, typename Trait<T>::reference x) { if(idx < 0 || idx >= maxThreadNum) return false; sourceMutex[idx].lock(); --sleepThreadNum; workFunc[idx] = f; this->x[idx] = x; running[idx] = true; sourceMutex[idx].unlock(); conditionVal[idx].notify_all(); return true; }
这东西是reduce,实际上就是吧传入函数和数据保存起来,之后 conditionVal[idx].notify_all();唤起线程,很简单的操作就实现了这些个功能
- 线程与线程池
- 线程池 线程优先级
- Executor线程,线程池
- 线程、多线程、线程池
- IOS-线程、线程池
- Java线程:线程池
- 线程和线程池
- 线程、多线程、线程池
- 线程、多线程、线程池
- 线程(六)线程池
- ExecutorService(线程池)+线程
- 线程和线程池
- 线程&线程池 简略
- 线程和线程池
- 线程池 线程锁
- 线程、线程池总结
- 线程与线程池
- 线程、锁、线程池
- 物体移动
- Spring+SpringMVC 配置事务管理无效原因及解决方案。
- 对swift中的Optional和闭包的理解
- SDUT 3327 顺序表应用4:元素位置互换之逆置算法
- HDU 5765 Bonds (二进制技巧)
- 线程池
- SQL_电力抢修工程插入数据语句
- mysql 双机异地热备份----快速理解mysql主从,主主备份原理及实践
- CSU-ACM2016暑假集训比赛6
- Android 5.0及以上系统实现沉浸式状态栏
- SELinux(Security-Enhanced Linux)的FTP配置设置
- POJ-----2631树的直径
- git基本操作
- MAC JDK版本切换