多线程在VC下和linux下的应用
一、概念介绍
线程是程序中一个单一的顺序控制流程.在单个程序中同时运行多个线程完成不同的工作,称为多线程.下面对进程和多线程的概念进行讲解和对比。
每个正在系统上运行的程序都是一个进程。每个进程包含一到多个线程。进程也可能是整个程序或者是部分程序的动态执行。线程是一组指令的集合,或者是程序的特殊段,它可以在程序里独立执行。也可以把它理解为代码运行的上下文。所以线程基本上是轻量级的进程,它负责在单个程序里执行多任务。通常由操作系统负责多个线程的调度和执行。
线程和进程的区别在于,子进程和父进程有不同的代码和数据空间,而多个线程则共享数据空间,每个线程有自己的执行堆栈和程序计数器为其执行上下文.多线程主要是为了节约CPU时间,发挥利用,根据具体情况而定. 线程的运行中需要使用计算机的内存资源和CPU。
二、vc中的多线程
vc中的多线程可以使用windows提供的API函数。线程创建函数如下:
HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, //安全性,NULL表示默认的安全性
SIZE_T dwStackSize, // 初始栈大小,以字节为单位,如果为0表示与调用该函数的线程相同的栈空间大小
LPTHREAD_START_ROUTINE lpStartAddress, // 线程函数
LPVOID lpParameter, // 函数的参数
DWORD dwCreationFlags, //创建选项,0表示立即激活
LPDWORD lpThreadId // 线程标识符);
线程的等待函数如下:
DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds);
vc中多线程的使用,以我的人脸识别为例子进行讲解(其中红色字体区域为多线程):
1 bool detect_and_draw( IplImage* image ); 2 const char* cascade_name ="haarcascade_frontalface_alt.xml"; //人脸检测要用到的分类器 3 4 bool detect_and_draw( IplImage* img, CvHaarClassifierCascade* cascade, CvMemStorage* storage) 5 { 6 double scale = 1.3; 7 IplImage* gray = cvCreateImage(cvSize(img->width,img->height), 8, 1); 8 IplImage* small_img = cvCreateImage( cvSize( cvRound (img->width/scale), 9 cvRound (img->height/scale)), 8, 1 ); 10 11 cvCvtColor( img, gray, CV_BGR2GRAY ); 12 cvResize( gray, small_img, CV_INTER_LINEAR ); 13 cvEqualizeHist( small_img, small_img ); 14 cvClearMemStorage( storage ); 15 16 if(cascade) 17 { 18 CvSeq* faces = cvHaarDetectObjects( small_img, cascade, storage, 1.1, 2, 0 , 19 cvSize(30, 30) ); 20 21 int facenum = faces ? faces->total : 0; 22 if(facenum) { 23 cvReleaseImage(&gray); 24 cvReleaseImage(&small_img); 25 return true; 26 } 27 } 28 cvReleaseImage(&gray); 29 cvReleaseImage(&small_img); 30 31 return false; 32 } 33 //全局变量,供线程共享使用 34 static int count = 0; //记录文件夹个数 35 HANDLE evtTerminate; //事件信号,标记是否所有子线程都执行完 36 37 static long ThreadCompleted = 0; //标记线程中已经完成的线程数目 38 typedef struct param{ //结构体记录传递给线程的参数 39 CString dirPath; 40 CString outFileName; 41 }param; 42 43 void FaceDetect(CString dirPath, CString fileName) 44 { 45 CvHaarClassifierCascade* cascade = 0; 46 CvMemStorage* storage = 0; 47 48 string dir = dirPath; 49 string outDir = dirPath; 50 if(fileName != "") 51 outDir += "\\" + fileName; 52 else 53 outDir += "\\homepageImgResult.txt"; 54 55 cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name, 0, 0, 0 ); //加载人脸检测所用到的分类器 56 if( !cascade ){ 57 AfxMessageBox("ERROR: Could not load classifier cascade"); 58 return; 59 } 60 storage = cvCreateMemStorage(0); 61 62 _finddata_t file; 63 long lf; 64 65 string files = dir + "\\homepageImg\\*.*"; 66 if((lf = _findfirst(files.c_str(), &file)) == -1) { 67 AfxMessageBox("Can't find files"); 68 return; 69 } 70 71 ofstream out; 72 out.open(outDir.c_str()); 73 vector<string> gifpath, gifname; 74 75 do { 76 string filename = file.name; 77 string filepath = dir + "\\homepageImg\\" + file.name; 78 if(filename != "." && filename != "..") { 79 if(filename.find(".gif") == string::npos) { 80 IplImage* image = cvLoadImage(filepath.c_str(), 1); 81 out << filename; 82 if(!image) 83 out << ",加载失败" << endl; 84 else { 85 if(detect_and_draw(image, cascade, storage)) //检测到人 86 out << ",yes"; 87 else 88 out << ",no"; 89 90 out << "," << image->width << "," << image->height; 91 out << endl; 92 cvReleaseImage(&image); 93 cvWaitKey(0); 94 95 } 96 } 97 } 98 }while(_findnext(lf, &file) == 0); 99 100 out.close(); 101 InterlockedIncrement(&ThreadCompleted); 102 if(ThreadCompleted == count) 103 SetEvent(evtTerminate); 104 } 105 106 107 void ThreadFunc(LPVOID content) //线程函数 108 { 109 param *p = (param*)content; //将线程参数还原出来 110 FaceDetect(p->dirPath, p->outFileName); 111 } 112 113 void CFaceDectectDlg::OnBrowse() 114 { 115 BROWSEINFO bi; 116 char selPath[MAX_PATH]; //存放选择的目录路径 117 118 bi.hwndOwner = m_hWnd; //指定对话框父窗口的句柄 119 bi.pidlRoot = NULL; //指定浏览的root目录 NULL代表桌面 120 bi.lpszTitle = "browse directory(universities):"; //树形视图上方显示的文字 121 bi.ulFlags = 0; //指定属性 122 bi.lpfn = NULL; //指定回调函数 123 bi.lParam = 0; //若指定回调函数 参数值传递给回调函数 124 bi.iImage = 0; //图标索引 125 bi.pszDisplayName = NULL; 126 127 LPITEMIDLIST pidlSel = SHBrowseForFolder(&bi); //打开文件夹浏览对话框 128 vector<CString> filePaths; 129 130 evtTerminate = CreateEvent(NULL, FALSE, FALSE, "terminate"); 131 132 133 if(pidlSel != NULL && SHGetPathFromIDList(pidlSel, selPath)) { 134 CString allFilePath; 135 CString errorMsg; 136 BOOL isFind; 137 138 allFilePath.Format("%s\\*", selPath); //选择目录下所子目录 139 CFileFind *finder = new CFileFind(); 140 isFind = finder->FindFile(allFilePath); 141 142 CString outFileName; 143 ((CEdit*)GetDlgItem(IDC_EDIT1))->GetWindowText(outFileName); 144 GetDlgItem(IDC_COUNT)->ShowWindow(true); 145 GetDlgItem(IDC_BUTTON1)->EnableWindow(false); 146 while(isFind) { 147 isFind = finder->FindNextFile(); //依次读取每个文件的内容 148 CString fileName = finder->GetFileName(); 149 if(fileName != "." && fileName != "..") { 150 CString filePath = finder->GetFilePath(); 151 filePaths.push_back(filePath); 152 } 153 } 154 155 count = filePaths.size(); 156 if(!count) { 157 errorMsg = "No university dir is found in"; 158 errorMsg += selPath; 159 AfxMessageBox(errorMsg); 160 } 161 162 163 for(int i = 0; i < count; ++i) { 164 CString filePath = filePaths.at(i); 165 unsigned long ThreadID; //线程id 166 param *params = new param; //动态申请空间给线程参数,如果为局部变量则在下次循环就释放了 167 params->dirPath = filePath; 168 params->outFileName = outFileName; 169 HANDLE hThread = CreateThread(NULL, //创建线程函数 170 0, 171 (LPTHREAD_START_ROUTINE)ThreadFunc, 172 params, 173 0, 174 &ThreadID); 175 } 176 177 WaitForSingleObject(evtTerminate, INFINITE); //等待所有子线程结束,即事件evtTerminate发生,主程序才继续往后执行 178 GetDlgItem(IDC_BUTTON1)->EnableWindow(true); 179 180 CString s; 181 s.Format("%d universities are found!", count); 182 GetDlgItem(IDC_NOTICE)->ShowWindow(true); 183 GetDlgItem(IDC_NOTICE)->SetWindowText(s); 184 185 GetDlgItem(IDC_COUNT)->SetWindowText("success,all has done!!!"); 186 AfxMessageBox("success,all has done!!!"); 187 188 finder->Close(); 189 delete finder; 190 } 191 else 192 AfxMessageBox("Invalid directory, Please choose again!"); 193 194 CloseHandle(evtTerminate); 195 UpdateData(true); 196 }
linux下多线程使用的是posix库中的pthread系列函数
pthread_create为创建线程函数int pthread_create(pthread_t*restrict tidp,const pthread_attr_t *restrict_attr,void*(*start_rtn)(void*),void *restrict arg);
在linux下面实现主线程等待子线程比较容易,只需使用 int pthread_join(pthread_t thread, void **retval);函数即可。
如果需要等待多个线程,我的方式是在创建的时候将这些线程id全部放到一个vector容器中;
当创建完线程后,遍历vector,对每个线程调用join,实现主进程等待所有线程的执行。
linux下多线程的人脸识别代码参见http://www.cnblogs.com/wulei-blog/archive/2013/05/09/3072211.html