Win32 多線程的建立方法和基本使用

來源:互聯網
上載者:User

 

總結Win32提供的建立多線程相關的API介面和基本的使用架構。

Ref:

MSDN: http://msdn.microsoft.com/zh-cn/library/y6h8hye8(v=VS.100)

Win32多線程的建立方法主要有:

(1)CreateThread()

(2)_beginthread()&&_beginthreadex()

(3)AfxBeginThread()

(4)CWinThread類

(1)CreateThread()

百度百科:http://baike.baidu.com/view/1191444.htm

函數原型:

view plaincopy to clipboardprint?
01.HANDLE CreateThread(
02.  LPSECURITY_ATTRIBUTES lpThreadAttributes,
03.  DWORD dwStackSize,
04.  LPTHREAD_START_ROUTINE lpStartAddress,
05.  LPVOID lpParameter,
06.  DWORD dwCreationFlags,
07.  LPDWORD lpThreadId);
08.}
HANDLE CreateThread(
  LPSECURITY_ATTRIBUTES lpThreadAttributes,
  DWORD dwStackSize,
  LPTHREAD_START_ROUTINE lpStartAddress,
  LPVOID lpParameter,
  DWORD dwCreationFlags,
  LPDWORD lpThreadId);
}

標頭檔:Windows.h

CreateThread是Win32提供的建立線程的最基礎的API,用於在主線程上建立一個線程。返回一個HANDLE控制代碼(核心對象)。

參數簡要說明:

lpThreadAttributes:線程屬性,用於設定線程的屬性,NULL表示使用預設的設定。dwStackSize:線程堆棧大小,使用0採用預設設定,windows會根據需要動態增加堆棧大小。lpStartAddress:指向線程函數的指標。lpParameter:向線程函數傳遞的參數。dwCreationFlags:線程標誌,CREATE_SUSPENDED表示建立一個掛起的線程,0表示建立後立即啟用線程。lpThreadId,先線程的ID(輸出參數)。

建立線程的代碼:

view plaincopy to clipboardprint?
01.#include "stdafx.h"
02.#include
03.
04.DWORD WINAPI ThreadProc(LPVOID lpParam)
05.{
06. printf("sub thread started\n");
07. printf("sub thread finished\n");
08. return 0;
09.}
10.
11.int main(int argc, char* argv[])
12.{
13. DWORD threadID;
14. HANDLE hThread;
15. hThread = CreateThread(NULL,0,ThreadProc,NULL,0,&threadID); // 建立線程
16.
17. return 0;
18.}
#include "stdafx.h"
#include

DWORD WINAPI ThreadProc(LPVOID lpParam)
{
printf("sub thread started\n");
printf("sub thread finished\n");
return 0;
}

int main(int argc, char* argv[])
{
DWORD threadID;
HANDLE hThread;
hThread = CreateThread(NULL,0,ThreadProc,NULL,0,&threadID); // 建立線程

return 0;
}
如果直接使用上面的代碼,那麼很可能沒有任何輸出,這是由於主線程建立了子線程後主線程繼續向下運行,子線程還沒來得及執行裡面的代碼主線程可能就結束了。這就需要另一個API來進行同步:WaitForSingleObject()。

與之對應的還有WaitForMultipleObjects,用於同步一組核心對象。(參考http://msdn.microsoft.com/zh-cn/site/ms686360擷取所有的同步函數(Synchronization Functions)的使用。

WaitForSingleObject原型:DWORD WINAPI WaitForSingleObject(__in HANDLE hHandle, __in DWORD dwMilliseconds);其中,第一個參數是要等待的核心對象的控制代碼,第二個參數是設定等待逾時時間,可以設定為INFINITE,表示一直等待直到有訊號觸發。

在核心對象使用完畢後,一般需要關閉,使用CloseHandle()函數,參數為核心物件控點。

所以,以下是一個最基本的使用CreateThread的例子:

view plaincopy to clipboardprint?
01.#include "stdafx.h"
02.#include
03.
04.DWORD WINAPI ThreadProc(LPVOID lpParam)
05.{
06. printf("sub thread started\n");
07. // TODO: Add your thread code here.
08. printf("sub thread finished\n");
09. return 0;
10.}
11.
12.int main(int argc, char* argv[])
13.{
14. DWORD threadID;
15. HANDLE hThread;
16. hThread = CreateThread(NULL,0,ThreadProc,NULL,0,&threadID); // 建立線程
17.
18. WaitForSingleObject(hThread,INFINITE);
19. CloseHandle(hThread); // 關閉核心對象
20.
21. return 0;
22.}
#include "stdafx.h"
#include

DWORD WINAPI ThreadProc(LPVOID lpParam)
{
printf("sub thread started\n");
// TODO: Add your thread code here.
printf("sub thread finished\n");
return 0;
}

int main(int argc, char* argv[])
{
DWORD threadID;
HANDLE hThread;
hThread = CreateThread(NULL,0,ThreadProc,NULL,0,&threadID); // 建立線程

WaitForSingleObject(hThread,INFINITE);
CloseHandle(hThread); // 關閉核心對象

return 0;
}
(2)_beginthread()&&_beginthreadex()

百度百科:http://baike.baidu.com/view/3029167.htm

MSDN:http://msdn.microsoft.com/zh-cn/library/kdzttdcb.aspx

函數原型:

view plaincopy to clipboardprint?
01.uintptr_t _beginthread( // NATIVE CODE
02. void( __cdecl *start_address )( void * ),
03. unsigned stack_size,
04. void *arglist
05.);
uintptr_t _beginthread( // NATIVE CODE
void( __cdecl *start_address )( void * ),
unsigned stack_size,
void *arglist
);

標頭檔:process.h

參數說明:第一個參數是線程函數的指標,第二個參數是堆棧大小,第三個參數是要傳遞給線程函數的參數列表。傳回值也是線程控制代碼(關於更多說明,參考MSDN)。
同樣,對於_beginthread()的同步,和CreateThread一樣可以使用WaitForSingleObject函數,CloseHandle()關閉核心對象。另外,_beginthread()的線程函數是無傳回值類型的,可以使用_endthread()線上程函數中結束線程。

下面是一個使用_beginthread()的基本的例子:

view plaincopy to clipboardprint?
01.#include "stdafx.h"
02.#include
03.#include
04.
05.void __cdecl ThreadProc(void *para)
06.{
07. printf("sub thread started\n");
08. // TODO: Add your thread code here.
09. printf("sub thread finished\n");
10. _endthread(); // 可以省略,隱含會調用。
11.}
12.
13.int main(int argc, char* argv[])
14.{
15. HANDLE hThread = (HANDLE)_beginthread(ThreadProc, 0, NULL);
16.
17. WaitForSingleObject(hThread,INFINITE);
18. CloseHandle(hThread);
19.}
#include "stdafx.h"
#include
#include

void __cdecl ThreadProc(void *para)
{
printf("sub thread started\n");
// TODO: Add your thread code here.
printf("sub thread finished\n");
_endthread(); // 可以省略,隱含會調用。
}

int main(int argc, char* argv[])
{
HANDLE hThread = (HANDLE)_beginthread(ThreadProc, 0, NULL);

WaitForSingleObject(hThread,INFINITE);
CloseHandle(hThread);
}另外,還有一個函數_beginthreadex(),可以簡單的認為_beginthread()為其簡化版,所以更多的時候是使用更簡單的_beginthread()了。
說明:在MSDN中可以看到一句很重要的提示,內容為“For an executable file linked with Libcmt.lib, do not call the Win32 ExitThread API; this prevents the run-time system from reclaiming allocated resources. _endthread and _endthreadex reclaim allocated thread resources and then call
ExitThread.”,簡單翻譯就是說,對於連結Libcmt.lib的可執行程式,不要使用Win32的線程退出函數(ExitThread),這會阻止運行時系統回收分配的資源,應該使用_endthread,它能回收分配的線程資源然後調用ExitThread。這個問題看似沒有提到CreateThread(),但是其實有關,這就是經常看到有些資料上堅決的說到”不要使用CreateThread建立線程,否則會記憶體流失“的來源了。

問題引出:CreateThread的記憶體流失問題(CreateThread和_beginthread的區別)

Related Topics:http://wenku.baidu.com/view/adede4ec4afe04a1b071dea4.html http://www.cnblogs.com/whiteyun/archive/2011/06/02/2067742.html ....

1. _beginthread也是通過CreateThread來建立線程的,只是_beginthread對其進行了一些封裝,將相關”資源“通過線程的本機存放區(TLS)傳遞給了線程函數的參數,然後在調用_endthread的時候,會將這些儲存的資源進行釋放。

2. 並不是所有的使用CreateThread的情況都會有記憶體流失。看了很多人的文章,只有http://wenku.baidu.com/view/adede4ec4afe04a1b071dea4.html的分析是最清晰的,我已經轉到http://dl.dbank.com/c03ljl2iud了,可下載查看(著作權歸原作者所有)。

總之,建議是使用_beginthread取代CreateThread來建立線程。

(3)AfxBeginThread():

很顯然,這是MFC中的Afx系列函數,一個在MFC中建立線程的全域函數。由於現在也不怎麼用MFC了,這裡就不多說了。

(4)CWinThread類:

很顯然,是MFC中建立線程的類,同上,不多說了。

歡迎補充!

(1)補充內容:

關於WaitForMultipleObjects在_beginthread無法使用的問題

問題:使用_beginthread建立多個線程,無法使用WaitForMultipleObjects來進行同步。

這個問題可以用下面的例子來測試:

view plaincopy to clipboardprint?
01.#include "stdafx.h"
02.#include
03.#include
04.
05.void __cdecl ThreadProc(void *para)
06.{
07. printf("sub thread started\n");
08. // TODO: Add your thread code here.
09. printf("sub thread finished\n");
10. _endthread(); // 可以省略,隱含會調用。
11.}
12.
13.int main(int argc, char* argv[])
14.{
15. DWORD threadID;
16. HANDLE hThread[10];
17. for(int i =0;i<10;i++)
18. hThread[i] = (HANDLE)_beginthread(ThreadProc,0,NULL);
19.
20. WaitForMultipleObjects(10, hThread,TRUE,INFINITE); //無法同步所有線程!
21. for(int i = 0;i<10;i++) {
22. CloseHandle(hThread);
23. }
24.}
#include "stdafx.h"
#include
#include

void __cdecl ThreadProc(void *para)
{
printf("sub thread started\n");
// TODO: Add your thread code here.
printf("sub thread finished\n");
_endthread(); // 可以省略,隱含會調用。
}

int main(int argc, char* argv[])
{
DWORD threadID;
HANDLE hThread[10];
for(int i =0;i<10;i++)
hThread[i] = (HANDLE)_beginthread(ThreadProc,0,NULL);

WaitForMultipleObjects(10, hThread,TRUE,INFINITE); //無法同步所有線程!
for(int i = 0;i<10;i++) {
CloseHandle(hThread);
}
}
期望的結果是程式能輸出10次的線程建立結束的訊息,但是實際運行發現,無法達到這麼多次數。為何?這是因為WaitForMultipleObjects在這裡無法正常工作。原因是:

_endthread()在結束線程的時候,會自動調用CloseHandle關閉核心對象。這就容易解釋了,如果提前關閉了核心對象,WaitForMultipleObjects會返回錯誤。那麼有沒有專門用於_beginthread建立的線程的同步方法呢,就我目前所知,好象是沒有的!要解決這裡的問題,可以分別調用WaitForSingleObject來同步,當然,使用其他一些變相的方法也是可以的,另外,上面的CloseHandle當然就可以不用再調用了。

總結:看來_beginthread也不是那麼好用。:)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.