AfxBeginThread
用戶界面線程和工做者線程都是由AfxBeginThread建立的。如今,考察該函數:MFC提供了兩個重載版的AfxBeginThread,一個用於用戶界面線程,另外一個用於工做者線程,分別有以下的原型和過程:編程
用戶界面線程的AfxBeginThread
用戶界面線程的AfxBeginThread的原型以下:
windows
[cpp] view plain copyapi
CWinThread* AFXAPI AfxBeginThread( 安全
CRuntimeClass* pThreadClass, 微信
int nPriority, 多線程
UINT nStackSize, ide
DWORD dwCreateFlags, 函數
LPSECURITY_ATTRIBUTES lpSecurityAttrs) this
其中:
參數1是從CWinThread派生的RUNTIME_CLASS類;
參數2指定線程優先級,若是爲0,則與建立該線程的線程相同;
參數3指定線程的堆棧大小,若是爲0,則與建立該線程的線程相同;
參數4是一個建立標識,若是是CREATE_SUSPENDED,則在懸掛狀態建立線程,在線程建立後線程掛起,不然線程在建立後開始線程的執行。
參數5表示線程的安全屬性,NT下有用。 url
工做者線程的AfxBeginThread
工做者線程的AfxBeginThread的原型以下:
[cpp] view plain copy
CWinThread* AFXAPI AfxBeginThread(
AFX_THREADPROC pfnThreadProc,
LPVOID pParam,
int nPriority,
UINT nStackSize,
DWORD dwCreateFlags,
LPSECURITY_ATTRIBUTES lpSecurityAttrs)
其中:
參數1 線程的入口函數,聲明必定要以下: UINT MyThreadFunction( LPVOID pParam );
參數2 傳遞入線程的參數,注意它的類型爲:LPVOID,因此咱們能夠傳遞一個結構體入線程.
參數三、四、5分別指定線程的優先級、堆棧大小、建立標識、安全屬性,含義同用戶界面線程。
附錄A:
結束線程的兩種方式
當你在後臺用線程來打印一些圖形時.有時在打印一部分後,你但願能夠停下來,那麼此如何讓線程中止呢.下
面會詳細的向你解釋要結束線程的兩種方式
1 : 這是最簡單的方式,也就是讓線程函數執行完成,此時線程正常結束.它會返回一個值,通常0是成功結束,
固然你能夠定義本身的認爲合適的值來表明線程成功執行.在線程內調用AfxEndThread將會直接結束線程,此時線程的一切資源都會被回收.
2 : 若是你想讓別一個線程B來結束線程A,那麼,你就須要在這兩個線程中傳遞信息.不論是工做者線程仍是界面線程,若是你想在線程結束後獲得它的確結果,那麼你能夠調用 ::GetExitCodeThread函數
線程的三種狀態:
運行一個線程:
m_lpThread = AfxBeginThread( Thread, NULL, THREAD_PRIORITY_NORMAL,
0, CREATE_SUSPENDED );//其中Thread成員函數要設置爲static類型
暫停一個線程:
m_lpThread ->SuspendThread();或者sleep(1000);//讓線程睡眠
喚醒一個線程:
m_lpThread ->ResumeThread();
經驗總結:
仍是老師的那個項目,之前因爲計算量太大,致使程序常常出現假死的現象,由於程序只有一個線程,該線程主要用於處理計算上了,而對於消息隊列的響應被忽略了。所以解決的辦法就是用兩個線程,一個線程用於計算,一個線程用於處理消息。
到網上找了一些資料,發如今MFC中把線程分爲兩類,一類爲界面線程,一類爲工做線程。二者的區別在於前都可以處理消息響應,然後者則不能。對於該項目來講,只要把計算的過程放到一個工做線程裏來進行就能夠了。
如今先試一下,我新建了一個對話框,上面添加兩個按鈕,一個是start 一個是dialog。前者用於開始計算,然後者則彈出一個消息框。而後向該對話框裏面添加一個死循環的函數
[cpp] view plain copy
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 與 CreateThread 的區別
簡言之: AfxBeginThread是MFC的全局函數,是對CreateThread的封裝。CreateThread是Win32 API函數,前者最終要調到後者。
1>.
具體說來,CreateThread這個 函數是windows提供給用戶的 API函數,是SDK的標準形式,在使用的過程中要考慮到進程的同步與互斥的關係,進程間的同步互斥等一系列會致使操做系統死鎖的因素,用起來比較繁瑣一些,初學的人在用到的時候可能會產生不可預料的錯誤,建議多使用AfxBeginThread,是編譯器對原來的CreateThread函數的封裝,用與MFC編程(固然,只要修改了項目屬性,console和win32項目都能調用)而_beginthread是C的運行庫函數。
2>
在使用AfxBeginThread時,線程函數的定義爲:UINT _yourThreadFun(LPVOID pParam)參數必須如此;
在使用CreateThread時,線程的函數定義爲: DWORD WINAPI _yourThreadFun(LPVOID pParameter)
二者實質是同樣的,
不過AfxBeginThread返回CWinThread指針,就是說它會new一個CWinThread對象,而這個對象在線程運行結束時是會自動刪除的,
CreatThread,它返回的是一個句柄,若是你不使用CloseHandle的話就能夠經過它安全的瞭解線程狀態,