• AfxBeginThread的介绍/基本用法


     

     

    AfxBeginThread 
       用户界面线程和工作者线程都是由AfxBeginThread创建的。现在,考察该函数:MFC提供了两个重载版的AfxBeginThread,一个用于用户界面线程,另一个用于工作者线程,分别有如下的原型和过程:

    用户界面线程的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* AFXAPI AfxBeginThread(
    AFX_THREADPROC pfnThreadProc, 
    LPVOID pParam,
    int nPriority, 
    UINT nStackSize, 
    DWORD dwCreateFlags,
    LPSECURITY_ATTRIBUTES lpSecurityAttrs)
    其中:
    参数1  线程的入口函数,声明一定要如下: UINT MyThreadFunction( LPVOID pParam );
    参数2 传递入线程的参数,注意它的类型为:LPVOID,所以我们可以传递一个结构体入线程.
    参数3、4、5分别指定线程的优先级、堆栈大小、创建标识、安全属性,含义同用户界面线程。

    附录A

    结束线程的两种方式
         当你在后台用线程来打印一些图形时.有时在打印一部分后,你希望可以停下来,那么此如何让线程停止呢.下

    面会详细的向你解释要结束线程的两种方式
         1 : 这是最简单的方式,也就是让线程函数执行完成,此时线程正常结束.它会返回一个值,一般0是成功结束,

    当然你可以定义自己的认为合适的值来代表线程成功执行.在线程内调用AfxEndThread将会直接结束线程,此时线程的一切资源都会被回收.
         2 : 如果你想让别一个线程B来结束线程A,那么,你就需要在这两个线程中传递信息.不管是工作者线程还是界面线程,如果你想在线程结束后得到它的确结果,那么你可以调用     ::GetExitCodeThread函数

    还是老师的那个项目,以前由于计算量太大,导致程序经常出现假死的现象,因为程序只有一个线程,该线程主要用于处理计算上了,而对于消息队列的响应被忽略了。因此解决的办法就是用两个线程,一个线程用于计算,一个线程用于处理消息。
          到网上找了一些资料,发现在MFC中把线程分为两类,一类为界面线程,一类为工作线程。两者的区别在于前都能够处理消息响应,而后者则不能。对于该项目来说,只要把计算的过程放到一个工作线程里来进行就可以了。
        现在先试一下,我新建了一个对话框,上面添加两个按钮,一个是start 一个是dialog。前者用于开始计算,而后者则弹出一个消息框。然后向该对话框里面添加一个死循环的函数
    UINT CMultithreadDlg::jisuan(LPVOID lpParam)
    {
    int i = 1;
    for (;;)
    {
       i+=i;
    }
    return 0;
    }
        然后在start按钮的响应函数上添加上jisuan(NULL);即可,现在运行程序,按下start按钮后,可以看到CPU使用率涨到了100%,这个时候再按dialog按钮无反应,拖动关闭窗口均无效。这就是前面提到的假死现象(实际上是真死,因为死循环了,如果不是死循环,而只是计算量太大才是假死)。

        下面用多线程的方法来解决,在start按钮的响应函数改为
    CWinThread* mythread = AfxBeginThread(
       jisuan,
       NULL,
       THREAD_PRIORITY_NORMAL,
       0,
       0,
       NULL
       );
        运行,结果发现有错error C2665: 'AfxBeginThread' : none of the 2 overloads can convert parameter 1 from type 'unsigned int (void *)' Generating Code...
    我就纳闷了,函数指针是对的啊,原来 线程函数可以且必须是全局函数或者是静态成员函数。
    所以我们在线程函数的声明中改为 static UINT jisuan(LPVOID lpParam);即可,然后运行程序,这时点击start,待CPU涨至100%后,点击dialog,弹出对话框了,拖动、关闭窗口均没问题了。

         其实上面的那个AfxBeginThread,除前面两个参数外,后面的都是默认参数,可以省略。而必须有的这两个参数,一个是线程函数的指针,一个是传递给这个函数的参数。实际中我们经常这样用 AfxBeginThread(ThreadProc,this);//把this传过去,就可以调用类的成员了. 这样线程函数就可以使用和操作类的成员了。千万要注意线程函数是静态类函数成员。

        线程是创建了,但是如果中途要暂停该怎么做呢?
        我们在创建线程的时候获得了一个CWinThread的指针,这是一个指向线程对象的指针,CWinThread类里面就有暂停与恢复的函数,下面我就演示一下。
    在原来的程序上进行改动。向对话框类里面添加一个CWinThread* 的成员变量,不用初始化为NULL,这样会报错的,因为它只能通过AfxBeginThread函数获得。把start里面的声明去掉。
    然后添加一个 pause 按钮向其响应函数里面添加代码 mythread->SuspendThread();   再添加一个 resume按钮,向其响应函数里面添加 mythread->ResumeThread();
        再运行程序,我们start之后,按下pause可以看到CPU恢复正常,然后resume,CPU又涨上去了,到此证明一切操作正常。

  • 相关阅读:
    SQL注入详解
    Nginx跨域及Https配置
    GET请求和POST请求的request和response的中文乱码问题
    创建Maven工程
    Maven环境变量配置
    Cookie&Session会话技术
    Maven库站
    20191002思维导图工具MindManager 000 033
    20190930-02 Redis持久化方式一:RDB及修改RDB的默认持久化策略 000 032
    Tomcat配置HTTPS方式生成安全证书
  • 原文地址:https://www.cnblogs.com/lvdongjie/p/4446516.html
Copyright © 2020-2023  润新知