C++ AfxBeginThread的介紹/基本用法
AfxBeginThread
用戶界面線程和工作者線程都是由AfxBeginThread創(chuàng)建的?,F(xiàn)在,考察該函數(shù):MFC提供了兩個(gè)重載版的AfxBeginThread,一個(gè)用于用戶界面線程,另一個(gè)用于工作者線程,分別有如下的原型和過(guò)程:
用戶界面線程的AfxBeginThread
用戶界面線程的AfxBeginThread的原型如下:
CWinThread* AFXAPI AfxBeginThread( CRuntimeClass* pThreadClass, int nPriority, UINT nStackSize, DWORD dwCreateFlags, LPSECURITY_ATTRIBUTES lpSecurityAttrs)
其中:
參數(shù)1是從CWinThread派生的RUNTIME_CLASS類;
參數(shù)2指定線程優(yōu)先級(jí),如果為0,則與創(chuàng)建該線程的線程相同;
參數(shù)3指定線程的堆棧大小,如果為0,則與創(chuàng)建該線程的線程相同;
參數(shù)4是一個(gè)創(chuàng)建標(biāo)識(shí),如果是CREATE_SUSPENDED,則在懸掛狀態(tài)創(chuàng)建線程,在線程創(chuàng)建后線程掛起,否則線程在創(chuàng)建后開(kāi)始線程的執(zhí)行。
參數(shù)5表示線程的安全屬性,NT下有用。
工作者線程的AfxBeginThread
工作者線程的AfxBeginThread的原型如下:
CWinThread* AFXAPI AfxBeginThread( AFX_THREADPROC pfnThreadProc, LPVOID pParam, int nPriority, UINT nStackSize, DWORD dwCreateFlags, LPSECURITY_ATTRIBUTES lpSecurityAttrs)
其中:
參數(shù)1 線程的入口函數(shù),聲明一定要如下: UINT MyThreadFunction( LPVOID pParam );
參數(shù)2 傳遞入線程的參數(shù),注意它的類型為:LPVOID,所以我們可以傳遞一個(gè)結(jié)構(gòu)體入線程.
參數(shù)3、4、5分別指定線程的優(yōu)先級(jí)、堆棧大小、創(chuàng)建標(biāo)識(shí)、安全屬性,含義同用戶界面線程。
附錄A:
結(jié)束線程的兩種方式
當(dāng)你在后臺(tái)用線程來(lái)打印一些圖形時(shí).有時(shí)在打印一部分后,你希望可以停下來(lái),那么此如何讓線程停止呢.下
面會(huì)詳細(xì)的向你解釋要結(jié)束線程的兩種方式
1 : 這是最簡(jiǎn)單的方式,也就是讓線程函數(shù)執(zhí)行完成,此時(shí)線程正常結(jié)束.它會(huì)返回一個(gè)值,一般0是成功結(jié)束,
當(dāng)然你可以定義自己的認(rèn)為合適的值來(lái)代表線程成功執(zhí)行.在線程內(nèi)調(diào)用AfxEndThread將會(huì)直接結(jié)束線程,此時(shí)線程的一切資源都會(huì)被回收.
2 : 如果你想讓別一個(gè)線程B來(lái)結(jié)束線程A,那么,你就需要在這兩個(gè)線程中傳遞信息.不管是工作者線程還是界面線程,如果你想在線程結(jié)束后得到它的確結(jié)果,那么你可以調(diào)用 ::GetExitCodeThread函數(shù)
還是老師的那個(gè)項(xiàng)目,以前由于計(jì)算量太大,導(dǎo)致程序經(jīng)常出現(xiàn)假死的現(xiàn)象,因?yàn)槌绦蛑挥幸粋€(gè)線程,該線程主要用于處理計(jì)算上了,而對(duì)于消息隊(duì)列的響應(yīng)被忽略了。因此解決的辦法就是用兩個(gè)線程,一個(gè)線程用于計(jì)算,一個(gè)線程用于處理消息。
到網(wǎng)上找了一些資料,發(fā)現(xiàn)在MFC中把線程分為兩類,一類為界面線程,一類為工作線程。兩者的區(qū)別在于前都能夠處理消息響應(yīng),而后者則不能。對(duì)于該項(xiàng)目來(lái)說(shuō),只要把計(jì)算的過(guò)程放到一個(gè)工作線程里來(lái)進(jìn)行就可以了。
現(xiàn)在先試一下,我新建了一個(gè)對(duì)話框,上面添加兩個(gè)按鈕,一個(gè)是start 一個(gè)是dialog。前者用于開(kāi)始計(jì)算,而后者則彈出一個(gè)消息框。然后向該對(duì)話框里面添加一個(gè)死循環(huán)的函數(shù)
UINT CMultithreadDlg::jisuan(LPVOID lpParam)
{
int i = 1;
for (;;)
{
i+=i;
}
return 0;
}
然后在start按鈕的響應(yīng)函數(shù)上添加上jisuan(NULL);即可,現(xiàn)在運(yùn)行程序,按下start按鈕后,可以看到CPU使用率漲到了100%,這個(gè)時(shí)候再按dialog按鈕無(wú)反應(yīng),拖動(dòng)關(guān)閉窗口均無(wú)效。這就是前面提到的假死現(xiàn)象(實(shí)際上是真死,因?yàn)樗姥h(huán)了,如果不是死循環(huán),而只是計(jì)算量太大才是假死)。
下面用多線程的方法來(lái)解決,在start按鈕的響應(yīng)函數(shù)改為
CWinThread* mythread = AfxBeginThread( jisuan, NULL, THREAD_PRIORITY_NORMAL, 0, 0, NULL );
運(yùn)行,結(jié)果發(fā)現(xiàn)有錯(cuò)error C2665: 'AfxBeginThread' : none of the 2 overloads can convert parameter 1 from type 'unsigned int (void *)' Generating Code...
我就納悶了,函數(shù)指針是對(duì)的啊,原來(lái) 線程函數(shù)可以且必須是全局函數(shù)或者是靜態(tài)成員函數(shù)。
所以我們?cè)诰€程函數(shù)的聲明中改為 static UINT jisuan(LPVOID lpParam);即可,然后運(yùn)行程序,這時(shí)點(diǎn)擊start,待CPU漲至100%后,點(diǎn)擊dialog,彈出對(duì)話框了,拖動(dòng)、關(guān)閉窗口均沒(méi)問(wèn)題了。
其實(shí)上面的那個(gè)AfxBeginThread,除前面兩個(gè)參數(shù)外,后面的都是默認(rèn)參數(shù),可以省略。而必須有的這兩個(gè)參數(shù),一個(gè)是線程函數(shù)的指針,一個(gè)是傳遞給這個(gè)函數(shù)的參數(shù)。實(shí)際中我們經(jīng)常這樣用 AfxBeginThread(ThreadProc,this);//把this傳過(guò)去,就可以調(diào)用類的成員了. 這樣線程函數(shù)就可以使用和操作類的成員了。千萬(wàn)要注意線程函數(shù)是靜態(tài)類函數(shù)成員。
線程是創(chuàng)建了,但是如果中途要暫停該怎么做呢?
我們?cè)趧?chuàng)建線程的時(shí)候獲得了一個(gè)CWinThread的指針,這是一個(gè)指向線程對(duì)象的指針,CWinThread類里面就有暫停與恢復(fù)的函數(shù),下面我就演示一下。
在原來(lái)的程序上進(jìn)行改動(dòng)。向?qū)υ捒蝾惱锩嫣砑右粋€(gè)CWinThread* 的成員變量,不用初始化為NULL,這樣會(huì)報(bào)錯(cuò)的,因?yàn)樗荒芡ㄟ^(guò)AfxBeginThread函數(shù)獲得。把start里面的聲明去掉。
然后添加一個(gè) pause 按鈕向其響應(yīng)函數(shù)里面添加代碼 mythread->SuspendThread(); 再添加一個(gè) resume按鈕,向其響應(yīng)函數(shù)里面添加 mythread->ResumeThread();
再運(yùn)行程序,我們start之后,按下pause可以看到CPU恢復(fù)正常,然后resume,CPU又漲上去了,到此證明一切操作正常。
具體 總結(jié)如下
AfxBeginThread創(chuàng)建線程
1.聲明線程函數(shù):
UINT StartDownloadThread(LPVOID pParam); // 下載線程,
2.創(chuàng)建線程:
CWinThread* m_pThread; // 線程對(duì)象指針
// 創(chuàng)建多線程
void CMyDownloadDlg::CreateThread(CDLoadThread* pDloadThread)
{
// 創(chuàng)建響應(yīng)線程,啟動(dòng)線程函數(shù)
m_pThread = AfxBeginThread(StartDownloadThread, (LPVOID)pDloadThread);
if(NULL == m_pThread)
{
TRACE("創(chuàng)建新的線程出錯(cuò)!\n");
return;
}
}
3.定義線程函數(shù)
UINT StartDownloadThread(LPVOID pParam)
{
// 為每個(gè)線程(任務(wù)數(shù))創(chuàng)建一個(gè)套接字來(lái)完成下載
CDLoadThread* pThis = (CDLoadThread*)pParam;
LONG indexTask = 0;
//indexTask = pThis->m_indexThread;
LONG indextNum = pThis->httpDload.m_index;
InterlockedIncrement(&pThis->httpDload.m_index); // 互斥方法訪問(wèn)共享資源,防止沖突
int ret = pThis->httpDload.CreateThreadFunc(indexTask, indextNum);
//TRACE("線程%d已成功完成!%d\n", index, ret);
return 0;
}
以上所述就是本文的全部?jī)?nèi)容了,希望大家能夠喜歡。
相關(guān)文章
C語(yǔ)言大廠面試技巧及strcpy()函數(shù)示例詳解
這篇文章主要為大家介紹了C語(yǔ)言面試技巧,以strcpy()函數(shù)為示例進(jìn)行分析詳解,有需要沖刺大廠的朋友們可以借鑒參考下,希望能夠有所幫助2021-11-11
C++ 關(guān)于MFC List Control 控件的總結(jié)
這篇文章主要介紹了C++ 關(guān)于MFC List Control 控件的總結(jié)的相關(guān)資料,十分的詳細(xì),有需要的朋友可以參考下2015-06-06
用C語(yǔ)言winform編寫(xiě)滲透測(cè)試工具實(shí)現(xiàn)SQL注入功能
本篇文章主要介紹使用C#winform編寫(xiě)滲透測(cè)試工具,實(shí)現(xiàn)SQL注入的功能。使用python編寫(xiě)SQL注入腳本,基于get顯錯(cuò)注入的方式進(jìn)行數(shù)據(jù)庫(kù)的識(shí)別、獲取表名、獲取字段名,最終獲取用戶名和密碼;使用C#winform編寫(xiě)windows客戶端軟件調(diào)用.py腳本,實(shí)現(xiàn)用戶名和密碼的獲取2021-08-08
如何在 C++ 中實(shí)現(xiàn)一個(gè)單例類模板
這篇文章主要介紹了如何在 C++ 中實(shí)現(xiàn)一個(gè)單例類模板,幫助大家更好的理解和學(xué)習(xí)c++編程,感興趣的朋友可以了解下2020-10-10
C語(yǔ)言代碼實(shí)現(xiàn)簡(jiǎn)單2048游戲
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)2048游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-12-12
解決C++ fopen按行讀取文件及所讀取的數(shù)據(jù)問(wèn)題
今天小編就為大家分享一篇解決C++ fopen按行讀取文件及所讀取的數(shù)據(jù)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-07-07

