需求
很多时候,需要用到多线程,但是线程每一次的分配都需要消耗时间,同时线程也不是无限制的开启的(需要固定一个数量)。
如果我们既想要固定数量,又不想每次都new一个线程,我们这么做就能满足要求:
a、固定一个数量,表示最大可使用线程的个数,threadCount=8;
b、在程序开始的时候,直接new出来threadCount个线程,假如存放到thread[threadCount-1]中
c、遇到一个任务,从thread[threadCount-1]中取出来一个线程,设置他的任务为Task,并且让threadCount-1,让此线程start
d、线程中的任务结束后让,threadCount+1
线程池
也可以从这里直接下载
把源码下载下来,解压得到一个文件夹和hpp文件
拷贝到(或者直接解压到boost目录中)
在vs中配置使用
打开vs(使用比较低版本的vs2010,要求比较高,同时没有c11可以使用,在vs2015也同样通过了测试)
如果还不会使用opencv和boost,可以参考blog文:
编译并使用opencv3.2:http://blog.csdn.net/zengraoli/article/details/70185803
编译并使用boost1.63:http://blog.csdn.net/zengraoli/article/details/70187556
测试例子的功能是浏览一个文件夹里面的1到10张图片,对比用单线程显示一张图片,和用8个线程同时显示的耗时对比
代码如下:
#include "stdafx.h" #include "stdio.h" #include "iostream" #include "vector" #include "windows.h" #include "boost/threadpool.hpp" #include "opencv2/opencv.hpp" using namespace std; using namespace boost::threadpool; using namespace cv; #define THREAD_COUNT 8 // 进程池的进程最大个数 #define FILE_NAME_LENGTH 64 // 文件名的长度 #define WINDOWS_NAME_LENGTH 32 // 窗口名的长度 #define SLEEP_SECOND 1000 // 每一个进程结束任务退出时,需要等待的时长 #define WAIT_KEY_SECOND 100 // opencv显示的等待时间 #define PIC_FOLDER_PATH "D:\\pic\\" // 表明显示图片所在的文件夹路径 #define PIC_BEGIN_NUM 1 // 文件夹下最小图片的下标(包含) #define PIC_END_NUM 11 // 文件夹下最大图片的下标(不包含) #pragma comment(lib, "lib/opencv_core320d.lib") #pragma comment(lib, "lib/opencv_highgui320d.lib") #pragma comment(lib, "lib/opencv_imgcodecs320d.lib") // 每个线程的任务 void Task(IplImage *p_img) { // boost::mutex::scoped_lock lock(m_io_monitor) //每个线程使用全局互斥来保证每次只有一个线程执行 char windows_name[WINDOWS_NAME_LENGTH]; sprintf_s(windows_name, "%d", boost::this_thread::get_id()); cvNamedWindow(windows_name, CV_WINDOW_AUTOSIZE); cvShowImage(windows_name, p_img); cvWaitKey(WAIT_KEY_SECOND); cvReleaseImage(&p_img);//释放图片 // cvDestroyAllWindows();//销毁窗口 Sleep(SLEEP_SECOND); } // 给线程池中的每一个线程分配任务,schedule会先把全部的任务接下来,如果没有线程空闲,则自动等待;wait遇到还有线程没有结束任务,那么其会进行阻塞等待 void ExecuteWithThreadpool() { //设置允许开启的线程数 pool tp(THREAD_COUNT); // opencv读取文件夹下的所有图片 char file_name[FILE_NAME_LENGTH]; IplImage *p_img; vector<IplImage *> v; for (int index = PIC_BEGIN_NUM; index < PIC_END_NUM; index++) { sprintf_s(file_name, "%s%d.png", PIC_FOLDER_PATH, index); p_img = cvLoadImage(file_name, 1); v.push_back(p_img); } vector<IplImage *>::iterator it; int index = 0; for (it = v.begin(); it != v.end(); it++) { cout << *it << endl; // 传入线程中作为参数 tp.schedule(boost::bind(Task, *it)); cout << "===========" << index++ << "===========" << endl; } tp.wait(); cout << "end." << endl; } // 显示一张图片 void ShowImg(IplImage *p_img, int index) { char windows_name[WINDOWS_NAME_LENGTH]; sprintf_s(windows_name, "%d", index); cvNamedWindow(windows_name, CV_WINDOW_AUTOSIZE); cvShowImage(windows_name, p_img); cvWaitKey(WAIT_KEY_SECOND); cvReleaseImage(&p_img);//释放图片 cvDestroyAllWindows();//销毁窗口 Sleep(SLEEP_SECOND); } // 不使用多线程的程序段 void ExecuteWithNotThread() { // opencv读取文件夹下的所有图片 char file_name[FILE_NAME_LENGTH]; IplImage *p_img; vector<IplImage *> v; for (int index = 1; index < 11; index++) { sprintf_s(file_name, "D:\\pic\\%d.png", index); p_img = cvLoadImage(file_name, 1); v.push_back(p_img); } vector<IplImage *>::iterator it; int index = 0; for (it = v.begin(); it != v.end(); it++) { cout << *it << endl; // 传入线程中作为参数 ShowImg(*it, index); cout << "===========" << index++ << "===========" << endl; } cout << "end." << endl; } int main() { double start, end; start = clock(); ExecuteWithNotThread(); end = clock(); printf("ExecuteWithNotThread:%fs \n", (end - start)/1000); start = clock(); ExecuteWithThreadpool(); end = clock(); printf("ExecuteWithThreadpool:%fs \n", (end - start)/1000); return 0; }
效果如下:
源代码下载地址:
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX