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又涨上去了,到此证明一切操作正常。
AfxBeginThread的介绍/基本用法的更多相关文章
- C++ AfxBeginThread的介绍/基本用法
AfxBeginThread 用户界面线程和工作者线程都是由AfxBeginThread创建的.现在,考察该函数:MFC提供了两个重载版的AfxBeginThread,一个用于用户界面线程,另一 ...
- oc-12-NSString 类简单介绍及用法
// 11-[掌握]NSString 类简单介绍及用法 #import <Foundation/Foundation.h> int main(int argc, const char * ...
- WorkFlow介绍及用法
WorkFlow介绍及用法 说起workflow大家肯定都不陌生,这里简单介绍一下salesforce中什么情况下使用workflow. 当你分配许多任务,定期发送电子邮件,记录修改时,可以通过自动配 ...
- Spring BeanFactory与FactoryBean的区别及其各自的详细介绍于用法
Spring BeanFactory与FactoryBean的区别及其各自的详细介绍于用法 1. BeanFactory BeanFactory,以Factory结尾,表示它是一个工厂类(接口),用于 ...
- vue第四单元(初识vue-在页面中直接引入vue框架-学习使用vue语法-vue的指令-介绍data用法-methods用法)
第四单元(初识vue-在页面中直接引入vue框架-学习使用vue语法-vue的指令-介绍data用法-methods用法) #课程目标 了解 vue 框架的特点 掌握创建 vue 实例 掌握 data ...
- ServletContext介绍和用法总结
ServletContext介绍和用法总结 学习总结 一.ServletContext 介绍 1. 概念 2. 作用 3. 获取 3.1 在实现类中获取 3.2 在 Spring 容器中获取 二.Se ...
- 08_android入门_android-async-http开源项目介绍及用法
android-async-http开源项目可以是我们轻松的获取网络数据或者向server发送数据.使用起来很easy,关于android-async-http开源项目的介绍内容来自于官方:http: ...
- JMS学习篇《一》ActiveMQ消息中间件的简单介绍与用法-概念篇
原创说明:本篇博文为本人原创作品,转载请注明出处 1.何为消息中间件 消息中间件是一种在分布式应用中互相交换信息的一种技术,常见的成熟消息中间件有:RabbitMQ.SonicMQ,activeMQ. ...
- Cookie、Session登陆验证相关介绍和用法
一.Cookie和Session 首先.HTTP协议是无状态的:所谓的无状态是指每次的请求都是独立的,它的执行情况和结果与前面的请求和之后的请求都无直接关系,它不会受前面的请求响应直接影响,也不会直接 ...
随机推荐
- Android 实时文件夹
实时文件夹是一种用来显示由某个ContentProvider提供的数据信息的桌面组件.要创建一个实时文件夹,必须要有两个方面的支持. 1,要定义一个用来创建实时文件夹的Activity. 2,所指定数 ...
- My way to Python - Day04 - 模块
re模块 什么是正则表达式 正则表达式,英文叫做Regular Expression.简单说,正则表达式就是一组规则,用于实现字符串的查找,匹配,以实现关于字符串的相关操作,比如替换,删除等. 正则表 ...
- .NET基础拾遗(3)字符串、集合和流2
二.常用集合和泛型 2.1 int[]是值类型还是引用类型? .NET中无论是存储值类型对象的数组还是存储引用类型的数组,其本身都是引用类型,其内存也都是分配在堆上的.所有的数组类型都继承自Syste ...
- 类型“XXX”的控件“XXXX”必须放在具有 runat=server 的窗体标记内。
问题:类型“Grid1”的控件“XXXX”必须放在具有 runat=server 的窗体标记内. 注:Grid1为表格的ID. 查找网上的解决大致为: 1)把Grid放到<form runat= ...
- Asp.net中实现同一用户名同时登陆,注销先前用户(转)
Web 项目中经常遇到的问题就是同一用户名多次登陆的问题,相应的解决办法也很多,总结起来不外乎这几种解决办法:将登陆后的用户名放到数据库表中:登陆后的用 户名放到Session中:登陆后的用户名放到A ...
- seajs模块压缩问题
在优化整理项目代码时,想使用seajs来把代码模块化.看了下官方5分钟上手教程,觉得很不错,也没多想就一直开发下去了,也没出什么问题.等一同事说把代码打包个放到设备上去测试一下,发现怎么也跑不起来,郁 ...
- phpmyadmin开启远程服务器连接
1.修改 braries/config.default.php,将 $cfg['AllowArbitraryServer'] 的值由 false 改成 true. 2.有其他需求的也可以自己在这里修 ...
- Python基础第五天
双层装饰器 字符串格式化 Python字符串格式有2种方式:百分号方式.format方式:建议使用format方式 1.百分号方式 格式:%[(name)][flags][width].[precis ...
- MvcPager概述
MvcPager 概述 MvcPager分页控件是在ASP.NET MVC Web应用程序中实现分页功能的一系列扩展方法,该分页控件的最初的实现方法借鉴了网上流行的部分源代码, 尤其是ScottG ...
- Scala学习笔记--隐式转换
隐式转换的规则:1.无歧义规则:隐式转换唯有不存在其他可插入转换的前提下才能插入 若编译器有两种方法修正x+y 如convert1(x)+y,convert2(x)+y,会报错2.单一调用规则:只尝 ...