多线程的使用

简介: 多线程的使用

背景:

       因为本人正在做芯片引脚缺陷检测,原理是当吸嘴将一个芯片吸过来时,需要隔一段时间(毫秒级)对其扫描识别,然后摄像机拍照获取图片,最后进行处理、检测。

       当识别到吸嘴处的芯片并拍照后,不可能先后对芯片引脚的宽度、间距、共线度进行顺序检测(太慢了),这时候多线程就发挥作用了,它可以通过多个子线程,同时对芯片引脚的各个指标进行检测。

       这里我用了单线程对引脚的共线度进行检测,后期进行其他检测时会继续加线程。

多线程与单线程的区别:

多线程:

      多线程指在单个程序中可以同时运行多个不同的线程执行不同的任务,线程是程序内的顺序控制流,只能使用分配给程序的资源和环境。多线程编程的目的,就是"最大限度地利用CPU资源",当某一线程的处理不需要占用CPU而只和I/O等资源打交道时,让需要占用CPU资源的其它线程有机会获得CPU资源。从根本上说,这就是多线程编程的最终目的。说白了就是提高系统的运行速度。

      一个进程可以包含一个或多个线程

      一个程序实现多个代码同时交替运行就需要产生多个线程

      CPU随机的抽出时间,让我们的程序一会做这件事情,一会做另外一件事情

单线程:

      当程序启动运行时,就自动产生一个线程,主方法main就在这个主线程上运行

生活举例:

你早上上班,正要打卡的时候,手机响了。。你如果先接了电话,等接完了,在打卡,就是单线程。

如果你一手接电话,一手打卡。就是多线程。

2件事的结果是一样的。。你接了电话且打了卡。

       MFC中,多线程依靠AfxBeginThread函数实现。该函数可用于创建界面线程和工作线程。对于工作线程,其原型为:

CWinThread* AfxBeginThread(AFX_THREADPROC pfnThreadProc,
                       LPVOID lParam,
                       int nPriority = THREAD_PRIORITY_NORMAL,
                       UINT nStackSize = 0,
                       DWORD dwCreateFlags = 0,
                       LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL
                       );//用于创建工作者线程

返回值: 成功时返回一个指向新线程的线程对象的指针,否则NULL。

pfnThreadProc : 线程的入口函数,声明一定要如下: UINT MyThreadFunction(LPVOID pParam),不能设置为NULL;

pParam : 传递入线程的参数,注意它的类型为:LPVOID,所以我们可以传递一个结构体入线程.

nPriority : 线程的优先级,一般设置为 0 .让它和主线程具有共同的优先级.

nStackSize : 指定新创建的线程的栈的大小.如果为 0,新创建的线程具有和主线程一样的大小的栈

dwCreateFlags : 指定创建线程以后,线程有怎么样的标志.可以指定两个值:

CREATE_SUSPENDED : 线程创建以后,会处于挂起状态,直到调用:ResumeThread

0 : 创建线程后就开始运行.

lpSecurityAttrs : 指向一个 SECURITY_ATTRIBUTES 的结构体,用它来标志新创建线程的安全性.如果为 NULL,

那么新创建的线程就具有和主线程一样的安全性.

如果要在线程内结束线程,可以在线程内调用 AfxEndThread.

一般直接用AfxBeginThread(ThreadProc, this);

参数一:子线程名称

界面线程和工作线程区别:

界面线程:处理消息,比如重绘,响应键盘鼠标等等跟消息有关的处理。

工作线程:一般是你自己写的用来处理数据的,比如操作数据库等等。

注意,工作者线程的函数必须是全局函数或静态成员函数,不能是普通的成员函数。

示例(结合定时器):

       这里我主要是模拟一下实际的工作场景,实际是当扫描到引脚处有芯片引脚后,才会进行后续处理。而我这里通过在定时器里面设置一个标志位(bool类型),只有当mflag = 1时,才会执行后续检测。

1)定义一个定时器消息

void CMFCApplication3Dlg::OnTimer(UINT_PTR nIDEvent)
{
  // TODO: 在此添加消息处理程序代码和/或调用默认值
  if( nIDEvent==1)  //作用是:如果有多个定时器,可以通过括号里面id区分
    {
     mflag = 1;    
     GetDlgItem(IDC_STATIC_ing)->SetWindowText("进行中...");
     static float m_nTime =0;//毫秒为单位
   m_nTime+=10;
     CString str;
     str.Format("时间:%.1f秒",m_nTime/10);
   //MessageBox(str);
     GetDlgItem(IDC_STATIC_TIME)->SetWindowText(str); 
  } 
  CDialogEx::OnTimer(nIDEvent);
}

注:这里面设置了一个bool mflag 充当标志位(用作线程开关)

2)创建主线程

//按钮点击执行
void CMFCApplication3Dlg::OnBnClickedButton4()
{
  //设置一个定时器,每隔一秒,调用一次消息OnTimer
  SetTimer(1,1000,NULL);
  // 创建响应线程,启动线程函数
  m_pThread = AfxBeginThread(DetectThread, (LPVOID)this);
  if(NULL == m_pThread)
  {
    TRACE("创建新的线程出错!\n");
    return;
  }
}

3)添加子线程定义为全局的

//添加子线程
UINT DetectThread(LPVOID  lParam)  
{  
   CMFCApplication3Dlg *pWnd = (CMFCApplication3Dlg *)lParam; //将窗口指针赋给无类型指针
   while(1)
   {
    if(mflag)
     {  
         pWnd->KMeansSegment();
        /*加核心代码,一般放计算量大的脏活累活*/
         mflag = 0;
    }
   }
   return 1;
}

注:

  • 当判断满足条件时,就返回函数值1,否则就返回函数值0。 如果在if(mflag)里加入 return 1后,每检测一次自动停止,需要手动再次检测。
  • 这里我在if(mflag)里面加了,Sleep(1000)暂停一秒,和每秒扫描一次定时器相对应,不知道合不合理。否则会出现,每秒钟运行好多次子线程函数;

4)子线程中的实现函数

void CMFCApplication3Dlg::KMeansSegment()

{

// 可将一些计算量不大的函数放入这里

}

5)暂停线程,定时器关闭

void CMFCApplication3Dlg::OnBnClickedButton5()
{
  // TODO: 在此添加控件通知处理程序代码
  m_pThread->SuspendThread();
  KillTimer(1);
}

6)恢复线程,定时器开启

void CMFCApplication3Dlg::OnBnClickedButton7()
{
  // TODO: 在此添加控件通知处理程序代码
  m_pThread->ResumeThread();
    SetTimer(1,1000,NULL);
}

7)结束线程

void CMFCApplication3Dlg::OnBnClickedButton6()
{
  // TODO: 在此添加控件通知处理程序代码
    mflag  = 1;
      AfxBeginThread( ExitApplicationThread, 0 );
}
//这个线程负责监控退出这个程序;
UINT  ExitApplicationThread( void * pParam )
{
              while(1)
                     {
                                if(mflag == 1 )
                                   {
                                         break;
                                   }
                                 Sleep(10);  //
                      }
               Sleep(100);//最好写上,确实等到别的线程退出;
               exit( 0); // 或者通知主程序退出,如 ::postMessage( afxGetApp()->m_pMainWind->m_hWnd, WM_CLOSE, 0, 0 );
              return 0;
}

找了如何安全结束线程,有的结束后过一会又自动运行了,有的结束后界面突然没有任何反应了,我这个是对话框直接关闭了,想找一个类似于暂停那种效果且不能恢复的,没有找到。不知道是不是和while循环有关,有知道的大神可以告知一下解决方案。

 

最后效果:

目录
相关文章
|
8月前
|
Java API 调度
|
27天前
|
安全 Java C++
多线程问题(四)
多线程问题(四)
21 0
|
28天前
|
Java 调度
多线程问题(一)
多线程问题(一)
24 0
|
1月前
|
Java API 调度
多线程知识篇
多线程知识篇
|
10月前
|
监控 Java API
多线程专题
多线程专题
|
9月前
|
调度 C++
多线程
多线程
|
10月前
|
安全 Linux C++
C++多线程实现
C++11支持语言级别的多线程编程,可以跨平台运行,支持windows/linux/mac等。
89 0
|
安全 程序员 C++
C++之多线程(二)
C++进阶之多线程下
74 0
|
调度
多线程之争用条件
多线程之争用条件
129 2
多线程之争用条件
|
Java Linux 调度
多线程必知必记的
《基础系列》
111 0
多线程必知必记的