zoukankan      html  css  js  c++  java
  • MFC的多线程操作

        记得用MFC做了一个图像自动修复软件,当时没有多线程操作这一概念,由于图像修复算法比较复杂,因此,当执行图像修复时,程序就像卡死了似得而不能做其他操作。其实MFC对这种情况有一种很好地解决方案,那就是采用多线程编程技术。以图像修复算法为例,由于其本身需要耗费大量时间,因此我们可以单独开一个线程让他执行修复而不影响主程序的操作。

    关于线程的一些概念,以及在VS2013下的实例:

    MFC中有两类线程,分别称之为工作者线程和用户界面线程。二者的主要区别在于工作者线程没有消息循环,而用户界面线程有自己的消息队列和消息循环。

    工作者线程没有消息机制,通常用来执行后台计算和维护任务,如冗长的计算过程(正适合图像修复算法),打印机的后台打印等。用户界面线程一般用于处理独立于其他线程执行之外的用户输入,响应用户及系统所产生的事件和消息等。但对于Win32的API编程而言,这两种线程是没有区别的,它们都只需线程的启动地址即可启动线程来执行任务。

    这两类线程的创建:

    用户界面线程的AfxBeginThread

    用户界面线程的AfxBeginThread的原型如下:
    CWinThread* AFXAPI AfxBeginThread(   CRuntimeClass* pThreadClass,   int nPriority,   UINT nStackSize,   DWORD dwCreateFlags,   LPSECURITY_ATTRIBUTES lpSecurityAttrs)
    其中:
    参数1是从CWinThread派生的RUNTIME_CLASS类;
    参数2指定线程优先级,如果为0,则与创建该线程的线程相同;
    参数3指定线程的堆栈大小,如果为0,则与创建该线程的线程相同;
    参数4是一个创建标识,如果是CREATE_SUSPENDED,则在悬挂状态创建线程,在线程创建后线程挂起,否则线程在创建后开始线程的执行。
    参数5表示线程的安全属性,NT下有用。

    工作者线程的AfxBeginThread

    工作者线程的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.结束线程的两种方式
     
    VS2013实例:
    创建一个线程执行函数(一般定义在类外)
    UINT MyThread(LPVOID pParam)
    {
        int ThreatEvent = *(int* )pParam;
        if (ThreatEvent == 0)
        AfxMessageBox(_T("MyThreadProc"), MB_OK);return 1;
    }

    强调一下这个LPVOID pParam,其可以传递任何简单的数据类型。但是必须得传递全局或者静态变量(这个不清楚是为什么);

    接下来开启线程:

    static int k;
        k = 0;
        AfxBeginThread(MyThread, &k);

    这个可以在OnShowWindow下测试一下。

    多线程之间的通信:

    通常情况下,一个次级线程要为主线程完成某种特定类型的任务,这就隐含着表示在主线程和次级线程之间需要建立一个通信的通道。一般情况下,有下面的几种方法实现这种通信任务:使用全局变量(这个看起来很LOW)、使用事件对象、使用消息。

    线程同步

    虽然多线程能给我们带来好处,但是也有不少问题需要解决。例如,对于像磁盘驱动器这样独占性系统资源,由于线程可以执行进程的任何代码段,且线程的运行是由系统调度自动完成的,具有一定的不确定性,因此就有可能出现两个线程同时对磁盘驱动器进行操作,从而出现操作错误;又例如,对于银行系统的计算机来说,可能使用一个线程来更新其用户数据库,而用另外一个线程来读取数据库以响应储户的需要,极有可能读数据库的线程读取的是未完全更新的数据库,因为可能在读的时候只有一部分数据被更新过。使隶属于同一进程的各线程协调一致地工作称为线程的同步。MFC提供了多种同步对象,下面我们只介绍最常用的四种:

    临界区(CCriticalSection)
    事件(CEvent)
    互斥量(CMutex)
    信号量(CSemaphore)
     
    通过这些类,我们可以比较容易地做到线程同步。
     
     
  • 相关阅读:
    nginx部署vue工程和反向代理nodejs工程
    memcache 原理 & 监测 & 查看状态 & stats & 结构
    CRT(secureCRT)中文显示研究&Linux中文字符显示
    Linux rz的使用
    htmlspecialschars与htmlentities的区别
    ie下php session不能用(域名的合法定义)
    常用生产环境的PHP安装参数
    XMLREADER/DOM/SIMPLEXML 解析大文件
    Linux中的小括号和大括号,${}/$()/()/{}/${var:-string}/${var:=string}/${var:+string}/${var:?string}/${var%pattern}/${var#pattern}/${var%%pattern}/${var##pattern}
    好用的window命令
  • 原文地址:https://www.cnblogs.com/meadow-glog/p/4542679.html
Copyright © 2011-2022 走看看