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分别指定线程的优先级、堆栈大小、创建标识、安全属性,含义同用户界面线程。
三、结束线程的两种方式
当你在后台用线程来打印一些图形时.有时在打印一部分后,你希望可以停下来,那么此如何让线程停止呢.下
面会详细的向你解释要结束线程的两种方式
1 : 这是最简单的方式,也就是让线程函数执行完成,此时线程正常结束.它会返回一个值,一般0是成功结束,
当然你可以定义自己的认为合适的值来代表线程成功执行.在线程内调用AfxEndThread将会直接结束线程,此时线程的一切资源都会被回收.
2 : 如果你想让别一个线程B来结束线程A,那么,你就需要在这两个线程中传递信息.不管是工作者线程还是界面线程,如果你想在线程结束后得到它的确结果,那么你可以调用 ::GetExitCodeThread函数
还是老师的那个项目,以前由于计算量太大,导致程序经常出现假死的现象,因为程序只有一个线程,该线程主要用于处理计算上了,而对于消息队列的响应被忽略了。因此解决的办法就是用两个线程,一个线程用于计算,一个线程用于处理消息。
到网上找了一些资料,发现在MFC中把线程分为两类,一类为界面线程,一类为工作线程。两者的区别在于前都能够处理消息响应,而后者则不能。对于该项目来说,只要把计算的过程放到一个工作线程里来进行就可以了。
现在先试一下,我新建了一个对话框,上面添加两个按钮,一个是start 一个是dialog。前者用于开始计算,而后者则弹出一个消息框。然后向该对话框里面添加一个死循环的函数
UINT CMultithreadDlg::jisuan(LPVOID lpParam)
{
int i = ;
for (;;)
{
i+=i;
}
return ;
}
然后在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创建线程
1.声明线程函数:
UINT StartDownloadThread(LPVOID pParam); // 下载线程,
2.创建线程:
CWinThread* m_pThread; // 线程对象指针
// 创建多线程
void CMyDownloadDlg::CreateThread(CDLoadThread* pDloadThread)
{
// 创建响应线程,启动线程函数
m_pThread = AfxBeginThread(StartDownloadThread, (LPVOID)pDloadThread); if(NULL == m_pThread)
{
TRACE("创建新的线程出错!\n");
return;
}
}
3.定义线程函数
UINT StartDownloadThread(LPVOID pParam)
{
// 为每个线程(任务数)创建一个套接字来完成下载
CDLoadThread* pThis = (CDLoadThread*)pParam;
LONG indexTask = ;
//indexTask = pThis->m_indexThread;
LONG indextNum = pThis->httpDload.m_index;
InterlockedIncrement(&pThis->httpDload.m_index); // 互斥方法访问共享资源,防止冲突
int ret = pThis->httpDload.CreateThreadFunc(indexTask, indextNum);
//TRACE("线程%d已成功完成!%d\n", index, ret);
return ;
}
AfxBeginThread的更多相关文章
- VC++ 结束线程 AfxBeginThread AfxEndThread
如果你的线程是从CWinThread继承出来的,结束自己就用AfxEndThread, 如果是外部调用的话,可以用PostThreadMessage(m_nThreadID, WM_QUIT,0,0) ...
- VC++ AfxBeginThread 与 CreateThread 的区别
简言之:AfxBeginThread是MFC的全局函数,是对CreateThread的封装. CreateThread是Win32 API函数,前者最终要调到后者.具体说来,CreateThre ...
- 使用MFC中的AfxBeginThread创建多线程
创建一个基于对话框的工程,工程名为CreateThreadRect 在CreateThreadRect.cpp中增加一个ThreadProc函数,代码如下 工作者线程的函数必须是全局函数或静态 ...
- C++ AfxBeginThread
计算从1+2+3...+100000=? 关键点 CWinThread* AfxBeginThread( AFX_THREADPROC pfnThreadProc, LPVOID pParam, in ...
- AfxBeginThread和AfxEndThread+内存泄露
ref http://blog.csdn.net/kut00/article/details/4209680 启动线程: CWinThread* AfxBeginThread( 线程函数, this ...
- 多线程 AfxBeginThread 与 CreateThread 的区别
简言之: AfxBeginThread是MFC的全局函数,是对CreateThread的封装. CreateThread是Win32 API函数,前者最终要调到后者. 1>.具体说来,Cr ...
- AfxBeginThread的介绍/基本用法
AfxBeginThread 用户界面线程和工作者线程都是由AfxBeginThread创建的.现在,考察该函数:MFC提供了两个重载版的AfxBeginThread,一个用于用户界面线程,另一 ...
- 工作线程AfxBeginThread的使用
工作线程通常用来执行一些后台任务,如:数据计算.后台杀毒等等.因为不需要创建窗口和处理用户消息,编写比较容易,在程序中只要调用AfxBeginThread 函数就可以创建并启动一个工作线程了. Afx ...
- 用户界面线程AfxBeginThread的使用
用户界面线程在运行时会有一个窗口界面和与其相对应的窗口函数,所以它可以通过响应消息来和用户进行交互. AfxBeginThread 函数原型如下: CWinThread *AfxBeginThread ...
- CreateThread、_beginthreadex和AfxBeginThread 的区别
CreateThread._beginthreadex和AfxBeginThread 创建线程好几个函数可以使用,可是它们有什么区别,适用于什么情况呢?参考了一些资料,写得都挺好的,这里做一些摘抄和整 ...
随机推荐
- localStorage存储对象,sessionStorage存储数组对象
前言 最近在用angular做商城购物车的功能模块,因为angular的watch监听,数据只要发生变化就能很方便的自动渲染页面.但随即出现的问题是,之前用户操作的样式都会被重置掉. 例如我勾选了几个 ...
- MySQL5.7+版本一些问题
今天有一个需求.我要用本地的Java调用远程服务器的MySQL,因为我的MySQL版本为5.7.2,即比较新的版本.网上找的很多都比较旧,故贴此贴. 无密码: 初次安装MySQL可能没有设置密码,网上 ...
- .37-浅析webpack源码之事件流make(4)
赶紧完结这个系列咯,webpack4都已经出正式版了. 之前的代码搜索到js文件的对应loader,并添加到了对象中返回,流程如下: this.plugin("factory", ...
- 创建第一个MVC应用程序
整个国庆期假,Insus.NET没有出门,在家静心修炼MVC.这意味着Insus.NET将来的日子里会以MVC为学习,开发,应用作为重点,不过现在才开始踏出第一步...... 路慢慢...... 下载 ...
- 【12】外观模式(Facade Pattern)
一.引言 在软件开发过程中,客户端程序经常会与复杂系统的内部子系统进行耦合,从而导致客户端程序随着子系统的变化而变化.然而为了将复杂系统的内部子系统与客户端之间的依赖解耦,从而就有了外观模式,也称作“ ...
- ArrayList初步
使用ArrayList,需添加引用:using System.Collections: 第一个例子: ArrayList list = new ArrayList(); list.Add(" ...
- 使用Picasso将加载的图片变成圆形
http://blog.it985.com/14794.html,感谢该作者 Picasso的GITHUB地址:https://github.com/square/picasso. 怎么实现各种各样的 ...
- art-template模板应用
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...
- python appium笔记(一):appium android环境配置及示例
(一) 简介 Appium是一个开源的自动化测试框架,可以用来测试基于iOS.Android和Firefox OS平台的原生和混合应用.该框架使用Selenium Webdriver,在执行测试时和 ...
- CSS 实例之滚动的图片栏
在一些网站上可以经常看到有一些图片进行持续不断的滚动,这个效果可以通过css的动画效果来实现.具体效果如下 主要原理是通过动画向左移动. 首先给出两组一样的图片(同一行上),让整体图片向左移动一组图片 ...