C++多線程實例(_beginThreadex創建多線程)

C++多線程(二)(_beginThreadex創建多線程)??

C/C++ Runtime 多線程函數


一 簡單實例(來自codeprojct:http://www.codeproject.com/useritems/MultithreadingTutorial.asp
主線程創建2個線程t1和t2,創建時2個線程就被掛起,后來調用ResumeThread恢復2個線程,是其開始執行,調用WaitForSingleObject等待2個線程執行完,然后推出主線程即結束進程。

/*??file?Main.cpp
?*
?*??This?program?is?an?adaptation?of?the?code?Rex?Jaeschke?showed?in
?*??Listing?1?of?his?Oct?2005?C/C++?User's?Journal?article?entitled
?*??"C++/CLI?Threading:?Part?I".??I?changed?it?from?C++/CLI?(managed)
?*??code?to?standard?C++.
?*
?*??One?hassle?is?the?fact?that?C++?must?employ?a?free?(C)?function
?*??or?a?static?class?member?function?as?the?thread?entry?function.
?*
?*??This?program?must?be?compiled?with?a?multi-threaded?C?run-time
?*??(/MT?for?LIBCMT.LIB?in?a?release?build?or?/MTd?for?LIBCMTD.LIB
?*??in?a?debug?build).
?*
?*??????????????????????????????????????John?Kopplin??7/2006
?
*/


#include?
<stdio.h>
#include?
<string>?????????????//?for?STL?string?class
#include?<windows.h>??????????//?for?HANDLE
#include?<process.h>??????????//?for?_beginthread()

using?namespace?std;


class?ThreadX
{
private:
??
int?loopStart;
??
int?loopEnd;
??
int?dispFrequency;

public:
??
string?threadName;

??ThreadX(?
int?startValue,?int?endValue,?int?frequency?)
??
{
????loopStart?
=?startValue;
????loopEnd?
=?endValue;
????dispFrequency?
=?frequency;
??}


??
//?In?C++?you?must?employ?a?free?(C)?function?or?a?static
??
//?class?member?function?as?the?thread?entry-point-function.
??
//?Furthermore,?_beginthreadex()?demands?that?the?thread
??
//?entry?function?signature?take?a?single?(void*)?and?returned
??
//?an?unsigned.
??static?unsigned?__stdcall?ThreadStaticEntryPoint(void?*?pThis)
??
{
??????ThreadX?
*?pthX?=?(ThreadX*)pThis;???//?the?tricky?cast
??????pthX->ThreadEntryPoint();???????????//?now?call?the?true?entry-point-function

??????
//?A?thread?terminates?automatically?if?it?completes?execution,
??????
//?or?it?can?terminate?itself?with?a?call?to?_endthread().

??????
return?1;??????????//?the?thread?exit?code
??}

??
void?ThreadEntryPoint()
??
{
?????
//?This?is?the?desired?entry-point-function?but?to?get
?????
//?here?we?have?to?use?a?2?step?procedure?involving
?????
//?the?ThreadStaticEntryPoint()?function.

????
for?(int?i?=?loopStart;?i?<=?loopEnd;?++i)
????
{
??????
if?(i?%?dispFrequency?==?0)
??????
{
??????????printf(?
"%s:?i?=?%d\n",?threadName.c_str(),?i?);
??????}

????}

????printf(?
"%s?thread?terminating\n",?threadName.c_str()?);
??}

}
;


int?main()
{
????
//?All?processes?get?a?primary?thread?automatically.?This?primary
????
//?thread?can?generate?additional?threads.??In?this?program?the
????
//?primary?thread?creates?2?additional?threads?and?all?3?threads
????
//?then?run?simultaneously?without?any?synchronization.??No?data
????
//?is?shared?between?the?threads.

????
//?We?instantiate?an?object?of?the?ThreadX?class.?Next?we?will
????
//?create?a?thread?and?specify?that?the?thread?is?to?begin?executing
????
//?the?function?ThreadEntryPoint()?on?object?o1.?Once?started,
????
//?this?thread?will?execute?until?that?function?terminates?or
????
//?until?the?overall?process?terminates.

????ThreadX?
*?o1?=?new?ThreadX(?0,?1,?2000?);

????
//?When?developing?a?multithreaded?WIN32-based?application?with
????
//?Visual?C++,?you?need?to?use?the?CRT?thread?functions?to?create
????
//?any?threads?that?call?CRT?functions.?Hence?to?create?and?terminate
????
//?threads,?use?_beginthreadex()?and?_endthreadex()?instead?of
????
//?the?Win32?APIs?CreateThread()?and?EndThread().

????
//?The?multithread?library?LIBCMT.LIB?includes?the?_beginthread()
????
//?and?_endthread()?functions.?The?_beginthread()?function?performs
????
//?initialization?without?which?many?C?run-time?functions?will?fail.
????
//?You?must?use?_beginthread()?instead?of?CreateThread()?in?C?programs
????
//?built?with?LIBCMT.LIB?if?you?intend?to?call?C?run-time?functions.

????
//?Unlike?the?thread?handle?returned?by?_beginthread(),?the?thread?handle
????
//?returned?by?_beginthreadex()?can?be?used?with?the?synchronization?APIs.

????HANDLE???hth1;
????unsigned??uiThread1ID;

????hth1?
=?(HANDLE)_beginthreadex(?NULL,?????????//?security
???????????????????????????????????0,????????????//?stack?size
???????????????????????????????????ThreadX::ThreadStaticEntryPoint,
???????????????????????????????????o1,???????????
//?arg?list
???????????????????????????????????CREATE_SUSPENDED,??//?so?we?can?later?call?ResumeThread()
???????????????????????????????????&uiThread1ID?);

????
if?(?hth1?==?0?)
????????printf(
"Failed?to?create?thread?1\n");

????DWORD???dwExitCode;

????GetExitCodeThread(?hth1,?
&dwExitCode?);??//?should?be?STILL_ACTIVE?=?0x00000103?=?259
????printf(?"initial?thread?1?exit?code?=?%u\n",?dwExitCode?);

????
//?The?System::Threading::Thread?object?in?C++/CLI?has?a?"Name"?property.
????
//?To?create?the?equivalent?functionality?in?C++?I?added?a?public?data?member
????
//?named?threadName.

????o1
->threadName?=?"t1";

????ThreadX?
*?o2?=?new?ThreadX(?-1000000,?0,?2000?);

????HANDLE???hth2;
????unsigned??uiThread2ID;

????hth2?
=?(HANDLE)_beginthreadex(?NULL,?????????//?security
???????????????????????????????????0,????????????//?stack?size
???????????????????????????????????ThreadX::ThreadStaticEntryPoint,
???????????????????????????????????o2,???????????
//?arg?list
???????????????????????????????????CREATE_SUSPENDED,??//?so?we?can?later?call?ResumeThread()
???????????????????????????????????&uiThread2ID?);

????
if?(?hth2?==?0?)
????????printf(
"Failed?to?create?thread?2\n");

????GetExitCodeThread(?hth2,?
&dwExitCode?);??//?should?be?STILL_ACTIVE?=?0x00000103?=?259
????printf(?"initial?thread?2?exit?code?=?%u\n",?dwExitCode?);

????o2
->threadName?=?"t2";

????
//?If?we?hadn't?specified?CREATE_SUSPENDED?in?the?call?to?_beginthreadex()
????
//?we?wouldn't?now?need?to?call?ResumeThread().

????ResumeThread(?hth1?);???
//?serves?the?purpose?of?Jaeschke's?t1->Start()

????ResumeThread(?hth2?);//你需要恢復線程的句柄 使用該函數能夠激活線程的運行

????
//?In?C++/CLI?the?process?continues?until?the?last?thread?exits.
????
//?That?is,?the?thread's?have?independent?lifetimes.?Hence
????
//?Jaeschke's?original?code?was?designed?to?show?that?the?primary
????
//?thread?could?exit?and?not?influence?the?other?threads.

????
//?However?in?C++?the?process?terminates?when?the?primary?thread?exits
????
//?and?when?the?process?terminates?all?its?threads?are?then?terminated.
????
//?Hence?if?you?comment?out?the?following?waits,?the?non-primary
????
//?threads?will?never?get?a?chance?to?run.

????WaitForSingleObject(?hth1,?INFINITE?);
????WaitForSingleObject(?hth2,?INFINITE?);
?????????? //WaitForSingleObject 函數用來檢測 hHandle 事件的信號狀態,當函數的執行時間超過 dwMilliseconds 就返回,
???? //但如果參數
dwMilliseconds INFINITE 時函數將直到相應時間事件變成有信號狀態才返回,否則就一直等待下去
???? //,直到
WaitForSingleObject 有返回直才執行后面的代碼

????GetExitCodeThread(?hth1,?
&dwExitCode?);
????printf(?
"thread?1?exited?with?code?%u\n",?dwExitCode?);

????GetExitCodeThread(?hth2,?
&dwExitCode?);
????printf(?
"thread?2?exited?with?code?%u\n",?dwExitCode?);
???????? //
//GetExitCodeThread這個函數是獲得線程的退出碼,  第二個參數是一個 DWORD的指針,
//用戶應該使用一個 DWORD 類型的變量去接收數據,返回的數據是線程的退出碼,
//第一個參數是線程句柄,用 CreateThread 創建線程時獲得到。
//通過線程退出碼可以判斷線程是否正在運行,還是已經退出。


????//?The?handle?returned?by?_beginthreadex()?has?to?be?closed
????
//?by?the?caller?of?_beginthreadex().

????CloseHandle(?hth1?);
????CloseHandle(?hth2?);

????delete?o1;
????o1?
=?NULL;

????delete?o2;
????o2?
=?NULL;

????printf(
"Primary?thread?terminating.\n");
}


二解釋
1)如果你正在編寫C/C++代碼,決不應該調用CreateThread。相反,應該使用VisualC++運行期庫函數_beginthreadex,推出也應該使用_endthreadex。如果不使用Microsoft的VisualC++編譯器,你的編譯器供應商有它自己的CreateThred替代函數。不管這個替代函數是什么,你都必須使用。

2)因為_beginthreadex和_endthreadex是CRT線程函數,所以必須注意編譯選項runtimelibaray的選擇,使用MT或MTD。

3) _beginthreadex函數的參數列表與CreateThread函數的參數列表是相同的,但是參數名和類型并不完全相同。這是因為Microsoft的C/C++運行期庫的開發小組認為,C/C++運行期函數不應該對Windows數據類型有任何依賴。_beginthreadex函數也像CreateThread那樣,返回新創建的線程的句柄。
下面是關于_beginthreadex的一些要點:
&8226;每個線程均獲得由C/C++運行期庫的堆棧分配的自己的tiddata內存結構。(tiddata結構位于Mtdll.h文件中的VisualC++源代碼中)。

&8226;傳遞給_beginthreadex的線程函數的地址保存在tiddata內存塊中。傳遞給該函數的參數也保存在該數據塊中。

&8226;_beginthreadex確實從內部調用CreateThread,因為這是操作系統了解如何創建新線程的唯一方法。

&8226;當調用CreatetThread時,它被告知通過調用_threadstartex而不是pfnStartAddr來啟動執行新線程。還有,傳遞給線程函數的參數是tiddata結構而不是pvParam的地址。

&8226;如果一切順利,就會像CreateThread那樣返回線程句柄。如果任何操作失敗了,便返回NULL

4) _endthreadex的一些要點:
&8226;C運行期庫的_getptd函數內部調用操作系統的TlsGetValue函數,該函數負責檢索調用線程的tiddata內存塊的地址。

&8226;然后該數據塊被釋放,而操作系統的ExitThread函數被調用,以便真正撤消該線程。當然,退出代碼要正確地設置和傳遞。

5)雖然也提供了簡化版的的_beginthread和_endthread,但是可控制性太差,所以一般不使用。

6)線程handle因為是內核對象,所以需要在最后closehandle

7)更多的API:

HANDLE GetCurrentProcess();

HANDLE GetCurrentThread();

DWORD GetCurrentProcessId();

DWORD GetCurrentThreadId()。

DWORD SetThreadIdealProcessor(HANDLE hThread,DWORD dwIdealProcessor);

BOOL SetThreadPriority(HANDLE hThread,int nPriority);

BOOL SetPriorityClass(GetCurrentProcess(),? IDLE_PRIORITY_CLASS);

BOOL GetThreadContext(HANDLE hThread,PCONTEXT pContext);BOOL SwitchToThread();

三注意
1)C++主線程的終止,同時也會終止所有主線程創建的子線程,不管子線程有沒有執行完畢。所以上面的代碼中如果不調用WaitForSingleObject,則2個子線程t1和t2可能并沒有執行完畢或根本沒有執行。
2)如果某線程掛起,然后有調用WaitForSingleObject等待該線程,就會導致死鎖。所以上面的代碼如果不調用resumethread,則會死鎖。

?

?

為什么要用C運行時庫的_beginthreadex代替操作系統的CreateThread來創建線程?

來源自自1999年7月MSJ雜志的《Win32 Q&A》欄目

你也許會說我一直用CreateThread來創建線程,一直都工作得好好的,為什么要用_beginthreadex來代替CreateThread,下面讓我來告訴你為什么。
回答一個問題可以有兩種方式,一種是簡單的,一種是復雜的。
如果你不愿意看下面的長篇大論,那我可以告訴你簡單的答案:_beginthreadex在內部調用了CreateThread,在調用之前_beginthreadex做了很多的工作,從而使得它比CreateThread更安全。


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/254392.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/254392.shtml
英文地址,請注明出處:http://en.pswp.cn/news/254392.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

halcon求取區域頂點

文章目錄簡介Halcon源代碼處理效果博主寫作不容易&#xff0c;孩子需要您鼓勵 萬水千山總是情 , 先點個贊行不行 簡介 使用halcon求取頂點的方法。 Halcon源代碼 read_image (Image1, 1.png)points_foerstner (Image1, 1, 2, 3, 200, 0.3, gauss, false, RowJunctions, …

從excel表中生成批量SQL,將數據錄入到數據庫中

excel表格中有許多數據&#xff0c;需要將數據導入數據庫中&#xff0c;又不能一個一個手工錄入&#xff0c;可以生成SQL&#xff0c;來批量操作。1.首先在第二行的H列&#xff0c;插入函數&#xff1a;CONCATENATE("INSERT INTO book (bookid, title, volume, author, u…

HDU-5895 Mathematician QSC

題目大意&#xff1a; 已知f[0] 0, f[1] 1, f[i] f[i-1] * 2 f[i-2]&#xff0c;且g[n] g[n-1] f[n] * f[n]&#xff0c;現在給出n&#xff0c;y&#xff0c;x&#xff0c;s&#xff0c;問你x^(g[n*y]) mod (s 1)的值為多少。 解題思路&#xff1a; 首先可以得到的是g[n…

C#的兩種類據類型:值類型和引用類型

目錄什么是值類型&#xff0c;什么是引用類型概念&#xff1a;值類型和引用類型區別什么是值類型&#xff0c;什么是引用類型 概念&#xff1a; 值類型直接存儲其值&#xff0c;而引用類型存儲對其值的引用。部署&#xff1a;托管堆上部署了所有引用類型。 引用類型&#xf…

ring0 ring3 kernel driver

intel cpu的權限訪問控制&#xff1a;ring0 ~ ring5. window、linux操作系統都只用了ring0&#xff0c;ring3&#xff0c;對應內核態和用戶態. 驅動程序工作在內核態&#xff0c;沒有main函數入口&#xff0c;而應用程序工作在用戶態。轉載于:https://www.cnblogs.com/yiii/p/6…

Linux 的多線程編程的高效開發經驗

轉自&#xff1a;http://www.chineselinuxuniversity.net/articles/22615.shtml 本文中我們針對 Linux 上多線程編程的主要特性總結出 5 條經驗&#xff0c;用以改善 Linux 多線程編程的習慣和避免其中的開發陷阱。在本文中&#xff0c;我們穿插一些 Windows 的編程用例用以對…

Visual C++中error spawning cl.exe解決辦法

| 版權聲明&#xff1a;本文為博主原創文章&#xff0c;未經博主允許不得轉載。 今天安裝Vc6.0的時候出現了一個error spawning cl.exe的錯誤&#xff0c;在網上找了一些資料&#xff0c;才知道這是因為路徑設置的問題引起的&#xff0c; “cl.exe”是VC真正的程序編譯器&…

C#整數數據類型

文章目錄博主寫作不容易&#xff0c;孩子需要您鼓勵 萬水千山總是情 , 先點個贊行不行 數據類型含義取值范圍sbyte有符號8位整數-128 ~ 127&#xff08;-2^7 ~ 2^7-1&#xff09;byte無符號8位整數0 ~ 255&#xff08;0 ~ 2^8-1&#xff09;short有符號16位整數-32768 ~ 3…

HEXA機器人榮獲CES Asia2018 創新獎

2019獨角獸企業重金招聘Python工程師標準>>> 6月13日至15日&#xff0c;亞洲消費電子展CES Asia 2018將在上海新國際博覽中心如期舉行。在活動到來前&#xff0c;美國消費技術協會&#xff08;CTA&#xff09;于5月24日&#xff0c;提前揭曉了“2018亞洲消費電子展創…

【bzoj3994】[SDOI2015]約數個數和 莫比烏斯反演

題目描述 設d(x)為x的約數個數&#xff0c;給定N、M&#xff0c;求 輸入 輸入文件包含多組測試數據。 第一行&#xff0c;一個整數T&#xff0c;表示測試數據的組數。接下來的T行&#xff0c;每行兩個整數N、M。輸出 T行&#xff0c;每行一個整數&#xff0c;表示你所求的答案…

Linux根文件系統結構再認識

Linux根文件系統結構再認識劉建文&#xff08;http://blog.csdn.net/keminlau &#xff09; INTRO 盡管Linux的根文件系統在形式表現上是一體的&#xff08;所有數據目錄均為根目錄下的子目錄&#xff09;&#xff0c;但實際它們是多個不同的【邏輯主體】&#xff08;為了實現…

C#浮點數據類型

文章目錄博主寫作不容易&#xff0c;孩子需要您鼓勵 萬水千山總是情 , 先點個贊行不行 數據類型含義取值范圍有效數字位數float32位浮點數1.5X10^-45 ~ 3.4X10^387double64位浮點數5.0X10^-324 ~ 1.7X10^30815 ~ 16 注意&#xff1a; 浮點數有一定的取值范圍和有效數字限制…

在Window10上使用Ubuntu終端

在Windows10上使用Ubuntu終端 習慣了ubuntu的開發&#xff0c;回到windows的command可以說是很絕望了。之前偶爾用windows時一直用git-bash來代替。但是發現windows已經添加了對ubuntu子系統的支持&#xff0c;那直接用不是更爽。 1.安裝 進入控制面板&#xff0c;開啟適用于Li…

httpClient實現微信公眾號消息群發

1、實現功能  向關注了微信公眾號的微信用戶群發消息。&#xff08;可以是所有的用戶&#xff0c;也可以是提供了微信openid的微信用戶集合&#xff09; 2、基本步驟 前提&#xff1a; 已經有認證的公眾號或者測試公眾賬號 發送消息步驟&#xff1a; 發送一個請求微信去獲取ac…

為靜態博客生成器WDTP移植了一款美美噠主題

前言 關于這個主題的移植后公布&#xff0c;我已經聯系了主題作者并取得同意&#xff0c;這個主題是一夜涕所寫的Sgreen&#xff0c;預覽圖見下 關于WDTP 就是一個很方便很便攜很快速的cpp編寫的帶gui跨平臺的開源的靜態博客生成器&#xff0c;軟件作者更新記錄在V站可以找到,軟…

TCP/IP數據包結構分析

一般來說&#xff0c;網絡編程我們只需要調用一些封裝好的函數或者組件就能完成大部分的工作&#xff0c;但是一些特殊的情況下&#xff0c;就需要深入的理解 網絡數據包的結構&#xff0c;以及協議分析。如&#xff1a;網絡監控&#xff0c;故障排查等…… IP包是不安全的&am…

C#decimal數據類型

文章目錄博主寫作不容易&#xff0c;孩子需要您鼓勵 萬水千山總是情 , 先點個贊行不行 為適應高精度的財務和貨幣計算的需要&#xff0c;C#提供了十進制decimal類型。decimal類型數據特征如下表所示&#xff1a; 數據類型含義取值范圍有效數字位數decimal128位高精度十進制…

世界杯快到了,看我用Python爬蟲實現(偽)球迷速成!

還有4天就世界杯了&#xff0c;作為一個資深&#xff08;偽&#xff09;球迷&#xff0c;必須要實時關注世界杯相關新聞&#xff0c;了解各個球隊動態&#xff0c;這樣才能在一堆球迷中如&#xff08;大&#xff09;魚&#xff08;吹&#xff09;得&#xff08;特&#xff09;水…

Bootstrap學習筆記(四)-----Bootstrap每天必學之表單

本文主要講解的是表單&#xff0c;這個其實對于做過網站的人來說&#xff0c;并不陌生&#xff0c;而且可以說是最為常用的提交數據的Form表單。本文主要來講解一下內容&#xff1a; 1.基本案例2.內聯表單3.水平排列的表單4.被支持的控件5.靜態控件6.控件狀態7.控件尺寸8.幫助文…

LVS--NAT模型配置

環境準備 管理IP地址角色備注192.168.11.131調度器&#xff08;Director&#xff09;對外提供VIP服務的地址為192.168.1.114192.168.11.132RS1 網關為192.168.11.131192.168.11.129RS2 網關為192.168.11.131將Directory開啟內核轉發 Linux系統默認是禁止數據包轉發的。所謂轉發…