C++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)
{
begin和start区别int i = 1;
for (;;)
{
i+=i;
}
return 0;
}
然后在start按钮的响应函数上添加上jisuan(NULL);即可,现在运⾏程序,按下start按钮后,可以看到C
PU使⽤率涨到了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 *)'
我就纳闷了,函数指针是对的啊,原来线程函数可以且必须是全局函数或者是静态成员函数。
所以我们在线程函数的声明中改为 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 = 0;
//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 0;
}
以上所述就是本⽂的全部内容了,希望⼤家能够喜欢。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论