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又涨上去了,到此证明一切操作正常。

时间: 2024-07-29 23:46:50

AfxBeginThread的介绍/基本用法的相关文章

C++ AfxBeginThread的介绍/基本用法

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

C++设计模式类库 Loki介绍与用法

C++设计模式类库 Loki介绍与用法 Loki是由Andrei编写的一个与<Modern C++ Design>(C++设计新思维)一书配套发行的C++代码库.它不仅把C++模板的功能发挥到了极致,而且把类似设计模式这样思想层面的东西通过库来提供.本篇文章介绍如何利用Loki来轻松地实现一些设计模式. 由于Loki使用了大量牛X到爆的模板技巧,对编译器的要求是很苛刻的,官方兼容列表里只列出了VC7.1以上版本及GCC3.4以上版本.如果你象我一样喜欢用C++Builder6或VC6,可以去下

unity3D游戏开发之iTween介绍和用法

unity3D游戏开发之iTween介绍和用法 一.iTween 介绍 iTween是一个动画库,作者创建它的目的就是最小的投入实现最大的产出.让你做开发更轻松,用它可以轻松实现各种动画,晃动,旋转,移动,褪色,上色,控制音频等等 二.iTween 原理 iTween的核心是数值插值,简单说就是给iTween两个数值(开始值,结束值),它会自动生成一些中间值. 三.iTween 下载:  从官网http://itween.pixelplacement.com下载 主要文件有两个iTween.cs

CSS后面部分介绍及用法

CSS后面部分介绍及用法一.伪类选择器:(标示是:{冒号})1.a:link(未访问的链接)2.a:visited (已访问过后的效果)3.a:hover (鼠标移动到链接上的效果)4.a:active (点击时的效果) 设置的顺序必须按照: :link  :visited  :hover  :active顺序写 二.伪元素 1.:first-child  选择元素的第一个子元素   2.:focus 获得焦点   3.:first-letter  获得第一个字 三.css样式   背景:背景和

Dotfuscator VS中自带的混淆器和压缩器简单介绍以及用法

Dotfuscator是VS里面一个自带的.NET混淆器和压缩器,它可以帮助您防止您的应用程序被反编译.同时,它还可以使得您的应用程序更加小巧以及高效. 闲话不多少了,下面介绍它的基础用法,从此让你编译后的程序变得更贱更神秘,大牛自行绕过啦,小虾可以看看学一下... 1:安装 下载并安装混淆器,这里有一个4.9破解版的(该软件来源于网络) 点击下载 提取码:a435 2:安装完毕后打开,如下图 3:选择你要加密混淆的DLL或EXE文件,我这里就直接用一个exe文件举例啦,如下图 \ 4:下边就开

&lt;04&gt;【掌握】14-NSString 类介绍及用法+【掌握】15-NSString 字符串长度计算方法

[掌握]14-NSString 类介绍及用法 下面介绍了四种字符串书写格式 第二种是本质,第一种是特殊的写法,一定要熟练:第三种(这个格式化输出也很常见)和第四种先放一放 #import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { @autoreleasepool { //NSString 是OC中字符串处理的类 //1.创建一个字符串(1) NSString *s = @"banzhang

df du 命令和磁盘分区介绍的用法介绍

4.1 df 命令 4.2 du 命令 4.3 磁盘分区 4.1 df命令 Linux中 df 命令的功能是用来检查 linux 服务器的文件系统的磁盘空间占用情况.可以利用该命令来获取硬盘被占用了多少空间,目前还剩下多少空间等信息. 格式:df [选项] [文件] [[email protected] ~]# df            #不带参数的,显示信息如下 文件系统                          1K-块    已用     可用 已用% 挂载点 /dev/mapp

rpm、yum工具的介绍和用法

rpm介绍 RPM 是RPM Package Manager(RPM软件包管理器)的缩写,这一文件格式名称虽然打上了RedHat的标志,但是其原始设计理念是开放式的,现在包括OpenLinux.S.u.S.E.以及Turbo Linux等Linux的分发版本都有采用,可以算是公认的行业标准了. 用法: rpm -ivh rpm包文件 //安装 #搭建实验环境,找到安装光盘ISO文件 [[email protected] Packages]# mount /dev/cdrom /mnt/  挂载光

Java关于Lombok的介绍和用法

前言 what?你的 Java 代码中还充斥着大量的 set/get 方法? 我们在刚开始学习 Java 语言的时候讲过,面向对象的三大特征就是封装,继承,和多态.在 Java 中,要保证封装性,需要将成员变量私有化,对外提供 set/get 方法来访问,虽然现在的 IDE,像 eclipse,IDEA都提供了快捷键,来生成 set/get 方法,但是在做项目的时候,一个 JavaBean 往往会有很多的成员变量,一个变量对应两个方法,如果有10几个成员变量,那么会对应20多个方法,也许还要去写