日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > c/c++ >内容正文

c/c++

C++多线程编程(入门实例)

發(fā)布時(shí)間:2023/12/18 c/c++ 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++多线程编程(入门实例) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

多線程在編程中有相當(dāng)重要的地位,我們?cè)趯?shí)際開(kāi)發(fā)時(shí)或者找工作面試時(shí)總能遇到多線程的問(wèn)題,對(duì)多線程的理解程度從一個(gè)側(cè)面反映了程序員的編程水平。

  其實(shí)C++語(yǔ)言本身并沒(méi)有提供多線程機(jī)制(當(dāng)然目前C++ 11新特性中,已經(jīng)可以使用std::thread來(lái)創(chuàng)建線程了,因?yàn)檫€沒(méi)有系統(tǒng)地了解過(guò),所以這里不提了。),但Windows系統(tǒng)為我們提供了相關(guān)API,我們可以使用他們來(lái)進(jìn)行多線程編程。

創(chuàng)建線程的API函數(shù)

HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,//SD:線程安全相關(guān)的屬性,常置為NULLSIZE_T dwStackSize,//initialstacksize:新線程的初始化棧的大小,可設(shè)置為0LPTHREAD_START_ROUTINE lpStartAddress,//threadfunction:被線程執(zhí)行的回調(diào)函數(shù),也稱為線程函數(shù)LPVOID lpParameter,//threadargument:傳入線程函數(shù)的參數(shù),不需傳遞參數(shù)時(shí)為NULLDWORD dwCreationFlags,//creationoption:控制線程創(chuàng)建的標(biāo)志LPDWORD lpThreadId//threadidentifier:傳出參數(shù),用于獲得線程ID,如果為NULL則不返回線程ID)/* lpThreadAttributes:指向SECURITY_ATTRIBUTES結(jié)構(gòu)的指針,決定返回的句柄是否可被子進(jìn)程繼承,如果為NULL則表示返回的句柄不能被子進(jìn)程繼承。dwStackSize:設(shè)置初始棧的大小,以字節(jié)為單位,如果為0,那么默認(rèn)將使用與調(diào)用該函數(shù)的線程相同的棧空間大小。 任何情況下,Windows根據(jù)需要?jiǎng)討B(tài)延長(zhǎng)堆棧的大小。lpStartAddress:指向線程函數(shù)的指針,函數(shù)名稱沒(méi)有限制,但是必須以下列形式聲明: DWORD WINAPI 函數(shù)名 (LPVOID lpParam) ,格式不正確將無(wú)法調(diào)用成功。lpParameter:向線程函數(shù)傳遞的參數(shù),是一個(gè)指向結(jié)構(gòu)的指針,不需傳遞參數(shù)時(shí),為NULL。dwCreationFlags:控制線程創(chuàng)建的標(biāo)志,可取值如下: (1)CREATE_SUSPENDED(0x00000004):創(chuàng)建一個(gè)掛起的線程(就緒狀態(tài)),直到線程被喚醒時(shí)才調(diào)用 (2)0:表示創(chuàng)建后立即激活。 (3)STACK_SIZE_PARAM_IS_A_RESERVATION(0x00010000):dwStackSize參數(shù)指定初始的保留堆棧的大小, 如果STACK_SIZE_PARAM_IS_A_RESERVATION標(biāo)志未指定,dwStackSize將會(huì)設(shè)為系統(tǒng)預(yù)留的值lpThreadId:保存新線程的id返回值:函數(shù)成功,返回線程句柄,否則返回NULL。如果線程創(chuàng)建失敗,可通過(guò)GetLastError函數(shù)獲得錯(cuò)誤信息。*/BOOL WINAPI CloseHandle(HANDLE hObject); //關(guān)閉一個(gè)被打開(kāi)的對(duì)象句柄 /*可用這個(gè)函數(shù)關(guān)閉創(chuàng)建的線程句柄,如果函數(shù)執(zhí)行成功則返回true(非0),如果失敗則返回false(0), 如果執(zhí)行失敗可調(diào)用GetLastError.函數(shù)獲得錯(cuò)誤信息。 */

?

多線程編程實(shí)例1

1 #include <iostream> 2 #include <windows.h> 3 using namespace std;4 5 DWORD WINAPI Fun(LPVOID lpParamter)6 {7 for (int i = 0; i < 10; i++)8 cout << "A Thread Fun Display!" << endl;9 return 0L; 10 } 11 12 int main() 13 { 14 HANDLE hThread = CreateThread(NULL, 0, Fun, NULL, 0, NULL); 15 CloseHandle(hThread); 16 for (int i = 0; i < 10; i++) 17 cout << "Main Thread Display!" << endl; 18 return 0; 19 }

  

  運(yùn)行結(jié)果:

  

?

  可以看到主線程(main函數(shù))和我們自己的線程(Fun函數(shù))是隨機(jī)交替執(zhí)行的。可以看到Fun函數(shù)其實(shí)只運(yùn)行了六次,這是因?yàn)橹骶€程運(yùn)行完之后將所占資源都釋放掉了,使得子線程還沒(méi)有運(yùn)行完。看來(lái)主線程執(zhí)行得有點(diǎn)快,讓它sleep一下吧。

  使用函數(shù)Sleep來(lái)暫停線程的執(zhí)行。

1 VOID WINAPI Sleep( 2 __in DWORD dwMilliseconds 3 );

dwMilliseconds表示千分之一秒,所以 Sleep(1000); 表示暫停1秒。

多線程編程實(shí)例2

1 #include <iostream> 2 #include <windows.h> 3 using namespace std;4 5 DWORD WINAPI Fun(LPVOID lpParamter)6 {7 for (int i = 0; i < 10; i++)8 {9 cout << "A Thread Fun Display!" << endl; 10 Sleep(200); 11 } 12 13 return 0L; 14 } 15 16 int main() 17 { 18 HANDLE hThread = CreateThread(NULL, 0, Fun, NULL, 0, NULL); 19 CloseHandle(hThread); 20 for (int i = 0; i < 10; i++) 21 { 22 cout << "Main Thread Display!" << endl; 23 Sleep(500); 24 } 25 26 return 0; 27 }

  運(yùn)行結(jié)果:

  

?

  程序是每當(dāng)Fun函數(shù)和main函數(shù)輸出內(nèi)容后就會(huì)輸出換行,但是我們看到的確是有的時(shí)候程序輸出換行了,有的時(shí)候確沒(méi)有輸出換行,甚至有的時(shí)候是輸出兩個(gè)換行。這是怎么回事?下面我們把程序改一下看看。

多線程編程實(shí)例3

1 #include <iostream> 2 #include <windows.h> 3 using namespace std;4 5 DWORD WINAPI Fun(LPVOID lpParamter)6 {7 for (int i = 0; i < 10; i++)8 {9 //cout << "A Thread Fun Display!" << endl; 10 cout << "A Thread Fun Display!\n"; 11 Sleep(200); 12 } 13 14 return 0L; 15 } 16 17 int main() 18 { 19 HANDLE hThread = CreateThread(NULL, 0, Fun, NULL, 0, NULL); 20 CloseHandle(hThread); 21 for (int i = 0; i < 10; i++) 22 { 23 //cout << "Main Thread Display!" << endl; 24 cout << "Main Thread Display!\n"; 25 Sleep(500); 26 } 27 28 return 0; 29 }

  運(yùn)行結(jié)果

  

?

  這時(shí)候,正如我們預(yù)期的,正確地輸出了我們想要輸出的內(nèi)容并且格式也是正確的。在這里,我們可以把屏幕看成是一個(gè)資源,這個(gè)資源被兩個(gè)線程所共用,加入當(dāng)Fun函數(shù)輸出了Fun Display!后,將要輸出endl(也就是清空緩沖區(qū)并換行,在這里我們可以不用理解什么是緩沖區(qū)),但此時(shí),main函數(shù)卻得到了運(yùn)行的機(jī)會(huì),此時(shí)Fun函數(shù)還沒(méi)有來(lái)得及輸出換行(時(shí)間片用完),就把CPU讓給了main函數(shù),而這時(shí)main函數(shù)就直接在Fun Display!后輸出Main Display!。

  另一種情況就是“輸出兩個(gè)換行”,這種情況就是比如輸出Main Display!并輸出endl后,時(shí)間片用完,輪到子線程占用CPU,子進(jìn)程上一次時(shí)間片用完時(shí)停在了Fun Display!,下一次時(shí)間片過(guò)來(lái)時(shí),剛好開(kāi)始輸出endl,此時(shí)就會(huì)“輸出兩個(gè)換行”。

  那么為什么我們把實(shí)例2改成實(shí)例3就可以正確的運(yùn)行呢?原因在于,多個(gè)線程雖然是并發(fā)運(yùn)行的,但是有一些操作(比如輸出一整段內(nèi)容)是必須一氣呵成的,不允許打斷的,所以我們看到實(shí)例2和實(shí)例3的運(yùn)行結(jié)果是不一樣的。它們之間的差異就是少了endl,而多了一個(gè)換行符\n

  那么,是不是實(shí)例2的代碼我們就不可以讓它正確的運(yùn)行呢?答案當(dāng)然是否定的,下面我就來(lái)講一下怎樣才能讓實(shí)例2的代碼可以正確運(yùn)行。這涉及到多線程的同步問(wèn)題。對(duì)于一個(gè)資源被多個(gè)線程共用會(huì)導(dǎo)致程序的混亂,我們的解決方法是只允許一個(gè)線程擁有對(duì)共享資源的獨(dú)占,這里我們用互斥量(Mutex)來(lái)進(jìn)行線程同步

  在使用互斥量進(jìn)行線程同步時(shí),會(huì)用到以下幾個(gè)函數(shù):

HANDLE WINAPI CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes, //線程安全相關(guān)的屬性,常置為NULLBOOL bInitialOwner, //創(chuàng)建Mutex時(shí)的當(dāng)前線程是否擁有Mutex的所有權(quán)LPCTSTR lpName //Mutex的名稱 ); /* MutexAttributes:也是表示安全的結(jié)構(gòu),與CreateThread中的lpThreadAttributes功能相同,表示決定返回的句柄是否可被子進(jìn)程繼承,如果為NULL則表示返回的句柄不能被子進(jìn)程繼承。 bInitialOwner:表示創(chuàng)建Mutex時(shí)的當(dāng)前線程是否擁有Mutex的所有權(quán),若為T(mén)RUE則指定為當(dāng)前的創(chuàng)建線程為Mutex對(duì)象的所有者,其它線程訪問(wèn)需要先ReleaseMutex lpName:Mutex的名稱 */

DWORD WINAPI WaitForSingleObject(HANDLE hHandle, //要獲取的鎖的句柄DWORD dwMilliseconds //超時(shí)間隔 );/* WaitForSingleObject:等待一個(gè)指定的對(duì)象(如Mutex對(duì)象),直到該對(duì)象處于非占用的狀態(tài)(如Mutex對(duì)象被釋放)或超出設(shè)定的時(shí)間間隔。除此之外,還有一個(gè)與它類(lèi)似的函數(shù)WaitForMultipleObjects,它的作用是等待一個(gè)或所有指定的對(duì)象,直到所有的對(duì)象處于非占用的狀態(tài),或超出設(shè)定的時(shí)間間隔。 hHandle:要等待的指定對(duì)象的句柄。dwMilliseconds:超時(shí)的間隔,以毫秒為單位;如果dwMilliseconds為非0,則等待直到dwMilliseconds時(shí)間間隔用完或?qū)ο笞優(yōu)榉钦加玫臓顟B(tài),如果dwMilliseconds 為INFINITE則表示無(wú)限等待,直到等待的對(duì)象處于非占用的狀態(tài)。 */

BOOL WINAPI ReleaseMutex(HANDLE hMutex);//說(shuō)明:釋放所擁有的互斥量鎖對(duì)象,hMutex為釋放的互斥量句柄

?

多線程實(shí)例4

1 #include <iostream>2 #include <windows.h>3 using namespace std;4 5 HANDLE hMutex = NULL;//互斥量6 //線程函數(shù)7 DWORD WINAPI Fun(LPVOID lpParamter)8 {9 for (int i = 0; i < 10; i++) 10 { 11 //請(qǐng)求一個(gè)互斥量鎖 12 WaitForSingleObject(hMutex, INFINITE); 13 cout << "A Thread Fun Display!" << endl; 14 Sleep(100); 15 //釋放互斥量鎖 16 ReleaseMutex(hMutex); 17 } 18 return 0L;//表示返回的是long型的0 19 20 } 21 22 int main() 23 { 24 //創(chuàng)建一個(gè)子線程 25 HANDLE hThread = CreateThread(NULL, 0, Fun, NULL, 0, NULL); 26 hMutex = CreateMutex(NULL, FALSE,"screen"); 27 //關(guān)閉線程 28 CloseHandle(hThread); 29 //主線程的執(zhí)行路徑 30 for (int i = 0; i < 10; i++) 31 { 32 //請(qǐng)求獲得一個(gè)互斥量鎖 33 WaitForSingleObject(hMutex,INFINITE); 34 cout << "Main Thread Display!" << endl; 35 Sleep(100); 36 //釋放互斥量鎖 37 ReleaseMutex(hMutex); 38 } 39 return 0; 40 }

?

  運(yùn)行結(jié)果:

  

總結(jié)

以上是生活随笔為你收集整理的C++多线程编程(入门实例)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。