多线程在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

posted @ 2013-05-11 21:06  whu-小磊  阅读(319)  评论(0编辑  收藏  举报