多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內(nèi)最全I(xiàn)T社區(qū)平臺 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當(dāng)前位置:首頁 > php開源 > php教程 > Windows下多線程編程(二)

Windows下多線程編程(二)

來源:程序員人生   發(fā)布時間:2016-07-26 13:34:25 閱讀次數(shù):2429次

線程的分類

1.     有消息循環(huán)線程

  •  MFC中有用戶界面線程,從CWinThread派生出1個新的類作為UI線程類CUIThread,然后調(diào)用AfxBeginthread(RUNTIME_CLASS(CUIThread));啟動線程。UI線程可以直接創(chuàng)建模態(tài)對話框,而不用擔(dān)心消息循環(huán)的問題,由于UI線程默許自帶消息循環(huán)。
  •  MFC非用戶界面線程,不能創(chuàng)建模態(tài)對話框,但是可以創(chuàng)建非模態(tài)對話框或普通窗口,但是必須自己寫消息循環(huán)。

  

復(fù)制代碼
MSG msg; while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); }
復(fù)制代碼

 

2.     無消息循環(huán)線程

  • MFC中的工作者線程
  • 其他沒有加消息循環(huán)的普通線程。

 

線程間的通訊

1.   同享內(nèi)存變量

l  由于線程是同享進(jìn)程內(nèi)存的,所以通過全局/靜態(tài)變量來進(jìn)行通訊效力最最高的。參數(shù)需要斟酌是不是加volitile。

l  通過傳遞的參數(shù),如援用和指針。參數(shù)需要斟酌是不是加volitile。

2.   消息通知

  • 如果是子線程向主線程通訊,由于主線程有消息循環(huán),所以子線程可以通過發(fā)送消息來向主線程通訊。通過消息通訊能夠避免使用全局變量帶來的耦合性。

SendMessage必須等待消息函數(shù)處理完成才返回,PostMessage則直接將消息放入消息隊列立即返回。所以SendMessage的消息參數(shù)可以是臨時變量,而PostMessage的消息參數(shù)必須保證足夠的生存周期。

  • 如果子線程有自定義的消息循環(huán),也能夠通過PostThreadMessage來指定線程通訊。

       

復(fù)制代碼
while(true) { if(GetMessage(&msg,0,0,0)) //get msgfrom message queue { switch(msg.message) { case MY_MSG: // Todo: break; } } };
復(fù)制代碼

 

3.   其他方式

  • 所有跨進(jìn)程的通訊方式,固然可以用于跨線程了。

 

線程之間的狀態(tài)

1.   異步

即多個線程彼此獨立,不受外部線程的影響。線程本身就是實現(xiàn)異步的1種方式。

2.   同步

即多個線程彼此依賴,線程A的計算結(jié)果是線程B的計算的條件,也就是說在開始線程B的計算之前必須等待線程A的計算完。

3.   互斥

即多個線程在操作同1個資源時,1個線程必須等另外一個線程結(jié)束了才能繼續(xù)操作。互斥與同步不同的地方是,互斥沒有前后關(guān)系。同1個資源,可以指全局變量,也能夠指1個文件對象或是其他的內(nèi)核對象。由于內(nèi)核對象是跨進(jìn)程的,所以更是跨線程的。

            等待函數(shù)

1.    概念

WaitForSingleObject函數(shù)是等待內(nèi)核對象從無信號狀態(tài)到有信號狀態(tài)或是超時即返回。也即無信號狀態(tài)時等待,有信號或超時立即返回。

WaitForMulitpleObjects函數(shù)是等待多個內(nèi)核對象從無信號狀態(tài)到有信號狀態(tài)或是超時即返回(可以指明是所有對象或是任1對象)。

Windows具有幾種內(nèi)核對象可以處于已通知狀態(tài)和未通知狀態(tài):進(jìn)程、線程、作業(yè)、文件、控制臺輸入/輸出/毛病流、事件、等待定時器、信號量、互斥對象。

2.    等待函數(shù)與內(nèi)核對象之間的關(guān)系

對象

無信號狀態(tài)

有信號狀態(tài)

成功等待副作用

進(jìn)程

進(jìn)程活動時

進(jìn)程終止時

線程

線程活動時

線程終止時

文件

I/O要求正在處理時

I/O要求結(jié)束時

控制臺輸入

不存在任何輸入

存在輸入時

文件修改通知

沒有任何文件修改通知

文件系統(tǒng)發(fā)現(xiàn)修改時

重置通知

自動重置事件

ResetEvent, PulseEvent或等待成功

當(dāng)調(diào)用SetEvent或PulseEvnet時

重置事件

人工重置事件

ResetEvent,或PulseEvent

當(dāng)調(diào)用SetEvent或PulseEvnet時

自動重置定時器

CancelWaitableTimer或等待成功

當(dāng)時間到時(SetWaitableTimer)

重置定時器

人工重置定時器

CancelWaitableTimer

當(dāng)時間到時(SetWaitableTimer)

信號量

等待成功

當(dāng)資源數(shù)量>0時(ReleaseSemaphore)

數(shù)量減1

互斥量

等待成功

當(dāng)未被線程具有時(ReleaseMutex)

獲得線程所有權(quán)

l 線程和進(jìn)程創(chuàng)建及運行時都是無信號狀態(tài),當(dāng)結(jié)束運行時變成有信號狀態(tài)。

l 自動重置的事件(FALSE)對象,當(dāng)?shù)却晒Φ臅r候,會被修改成無信號狀態(tài)。

l 信號量對象,當(dāng)調(diào)用ReleaseSemaphore(數(shù)量加1),處于有信號狀態(tài),WaitForSingleObject會被觸發(fā)并且立行將信號數(shù)量減1.

 

 

        用戶模式與內(nèi)核模式的優(yōu)缺點

1.   用戶模式

優(yōu)點:線程同步機制速度快

缺點:容易墮入死鎖狀態(tài)多個進(jìn)程之間的線程同步會出現(xiàn)問題。(比如競爭資源、死鎖)

2.   內(nèi)核模式

優(yōu)點:支持多個進(jìn)程之間的線程同步,避免死鎖

缺點:線程同步機制速度慢,線程必須從用戶模式轉(zhuǎn)為內(nèi)核模式。這個轉(zhuǎn)換需要很大的代價:來回1次需要占用x 8 6平臺上的大約1 0 0 0個C P U周期。

 

 

線程間的狀態(tài)處理

1.   線程的異步

由于線程本身就是異步的。

2.   線程的同步

線程的同步主要是通過事件(Event)內(nèi)核對象、信號量(Semaphore)內(nèi)核對象和互斥量(Mutex)內(nèi)核對象。由于都是內(nèi)核對象,所以不但可以跨線程操作,還可以跨進(jìn)程同步。

1.      線程的同步

線程的同步主要是通過事件(Event)內(nèi)核對象、信號量(Semaphore)內(nèi)核對象和互斥量(Mutex)內(nèi)核對象。由于都是內(nèi)核對象,所以不但可以跨線程操作,還可以跨進(jìn)程同步。

事件(Event)內(nèi)核對象

事件分兩種類型:人工重置事件和自動重置事件,前者在觸發(fā)WaitForSingleObject以后需要手動調(diào)用ResetEvent將事件設(shè)置為無信號;而后者在觸發(fā)WaitForSingleObject以后自動將事件設(shè)置為無信號狀態(tài)。

經(jīng)常使用函數(shù):

CreateEvent,創(chuàng)建事件對象。

OpenEvent,打開已創(chuàng)建的事件對象,可以跨進(jìn)程打開。

SetEvent,將事件對象設(shè)置為有信號狀態(tài)。

ResetEvent,將事件對象設(shè)置為無信號狀態(tài)。

PulseEvent,將事件對象設(shè)置為有信號狀態(tài),然后又設(shè)置為無信號狀態(tài),此函數(shù)不經(jīng)常使用。

復(fù)制代碼
HANDELg_hEvent; int Main() { g_hEvent =CreateEvent(NULL, TRUE, FALSE, NULL); _beginthreadex(NULL,0, ThreadFun1, 0); _beginthreadex(NULL,0, ThreadFun2, 0); SetEvnet(g_hEvent);// } DWORD WINAPIThreadFun1(PVOID pParam) { WaitForSingleObject(g_hEvent); // Todo... SetEvent(g_hEvnet); return 0; } DWORD WINAPIThreadFun2(PVOID pParam) { WaitForSingleObject(g_hEvent); // Todo... SetEvent(g_hEvnet); return 0; }
復(fù)制代碼

 

注意:如果上面創(chuàng)建的是人工重置事件,則兩個線程函數(shù)都將履行。如果是自動重置事件,則只能履行1個線程,且不能保證哪個線程先履行。如果要保證1個線程先履行,可以添加事件對象用來確保指定線程已履行,不能通過代碼的前后順序確保線程已履行。

2.      信號量(Semaphore)內(nèi)核對象

信號量的使用規(guī)則:

當(dāng)前信號量資源數(shù)大于0,則標(biāo)記為有信號狀態(tài)。

當(dāng)前信號量資源數(shù)為0,則標(biāo)記為無信號狀態(tài)。

信號量資源數(shù)不能為負(fù),且最大不能超過指定數(shù)量。

經(jīng)常使用函數(shù):

CreateSemaphore,創(chuàng)建信號量對象。

OpenSemaphore,打開指定信號量對象,可以跨進(jìn)程。

ReleaseSemaphoer,資源計算加1。

復(fù)制代碼
HANDELg_hSema[2]; int Main() { g_hSema[0] =CreateSemaphore(NULL, 1, 1, NULL); g_hSema[1] =CreateSemaphore(NULL, 0, 1, NULL); _beginthreadex(NULL,0, ThreadFun1, 0); _beginthreadex(NULL,0, ThreadFun2, 0); } DWORD WINAPIThreadFun1(PVOID pParam) { WaitForSingleObject(g_hSema[0]); // Todo... ReleaseSemaphoer(g_hSema[1]); return 0; } DWORD WINAPIThreadFun2(PVOID pParam) { WaitForSingleObject(g_hSema[1]); // Todo... ReleaseSemaphoer(g_hSema[0]); return 0; }
復(fù)制代碼

 

這樣就可以夠保證ThreadFun1履行完了,再履行ThreadFun2,然后再履行ThreadFun1,并且保證每一個線程函數(shù)只能被調(diào)用1次.

3.      互斥量(Mutex)內(nèi)核對象

互斥量內(nèi)核對象確保線程具有單個資源的互斥訪問權(quán)。在行動特性上,互斥量與臨界區(qū)的1樣。只不過,互斥量是內(nèi)核對象,使用時需要從用戶模式切換到內(nèi)核模式,比較耗時。但正由于是內(nèi)核對象,所以互斥量能夠跨進(jìn)程,并且能夠設(shè)置超時時間,這是它比臨界區(qū)靈活的地方。

經(jīng)常使用函數(shù):

CreateMutex,創(chuàng)建互斥量對象。

OpenMutex,打開指定互斥量對象,可以跨進(jìn)程。

ReleaseMutex,釋放互斥量,對象被標(biāo)記為有信號狀態(tài),觸發(fā)WaitForSingleObject。

互斥量和臨界區(qū)1樣,具有1個線程具有權(quán)的概念,即當(dāng)前互斥量和當(dāng)前臨界區(qū)的釋放只能由當(dāng)前線程釋放,其他線程釋放無效。由于互斥量是內(nèi)核對象,如果線程已終止,但是其所屬的互斥量仍然沒有釋放,內(nèi)核管理器會自動釋放。臨界區(qū)沒有這個功能,由于臨界區(qū)不是內(nèi)核對象,所以臨界區(qū)如果沒有正確釋放會致使死鎖。

HANDLECreateMutex(  LPSECURITY_ATTRIBUTESlpMutexAttributes,

  BOOL bInitialOwner,  LPCTSTR lpName);

bInitialOwner標(biāo)記是不是由創(chuàng)建線程具有線程所有權(quán),TRUE表示創(chuàng)建者具有,F(xiàn)ALSE表示創(chuàng)建者不具有,則是第1個調(diào)用WaitForSingleObject的線程將取得線程所有權(quán)。

復(fù)制代碼
HANDELg_hMutex; int Main() { g_hMutex =CreateMutex(NULL,FALSE); _beginthreadex(NULL,0, ThreadFun1, 0); _beginthreadex(NULL,0, ThreadFun2, 0); } DWORD WINAPIThreadFun1(PVOID pParam) { WaitForSingleObject(g_hMutex); // Todo... ReleaseMutex(g_hMutex); return 0; } DWORD WINAPIThreadFun2(PVOID pParam) { WaitForSingleObject(g_hMutex); // Todo... ReleaseMutex(g_hMutex); return 0; }
復(fù)制代碼

 

兩個函數(shù)誰先調(diào)用,誰即獲得線程所有權(quán)。如果想指定線程先運行,需要判斷指定線程已履行以后再創(chuàng)建新線程,不能依托線程的代碼創(chuàng)建前后順序。

3.   線程的互斥

像互斥量對象一樣可以到達(dá)互斥的效果,只是互斥量功能更豐富,并且如果是簡單的資源互斥,使用臨界區(qū)的效力更優(yōu)。

臨界區(qū)(Critical Section)是1段供線程獨占式訪問的代碼,也就是說若有1線程正在訪問該代碼段,其它線程想要訪問,只能等待當(dāng)前線程離開該代碼段方可進(jìn)入,這樣保證了線程安全。他工作于用戶級(相對內(nèi)核級),在Window系統(tǒng)中CRITICAL_SECTION實現(xiàn)臨界區(qū)相干機制。

經(jīng)常使用函數(shù):

voidInitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection)  // 初始化臨界區(qū)

voidEnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection)       // 進(jìn)入臨界區(qū)

voidLeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection)       // 離開臨界區(qū)

voidDeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection)      // 釋放臨界區(qū)資源

由于臨界區(qū)具有線程所有權(quán)這個概念,即進(jìn)入臨界區(qū)的線程才有權(quán)釋放臨界區(qū)。由于必須當(dāng)前線程進(jìn)入和釋放,更多的時候,臨界區(qū)是在1個函數(shù)里使用,為了確保不會由于中間退出函數(shù)致使沒有釋放,我們可以用以下方式來確保釋放。

復(fù)制代碼
class Mutex { public: Mutex() {InitializeCriticalSection(section); } ~Mutex() { DeleteCriticalSection(section);} void Enter() {EnterCriticalSection(section); } void Leave() {LeaveCriticalSection(section); } struct Lock; protected: Mutex(const Mutex&); Mutex& operator=(const Mutex&); CRITICAL_SECTION section; }; structMutex::Lock { Mutex& s; Lock(Mutex& s) : s(s) { s.Enter(); } ~Lock() { s.Leave(); } }; DWORD WINAPIThreadFun(PVOID pParam) { Mutex::Locklock(mutex); // Todo... return 0; }
復(fù)制代碼

 

注意

1.      注意所有內(nèi)核對象在結(jié)束時都需要調(diào)用closeHandle()。

2.      跨線程調(diào)用MFC對象函數(shù)都是不安全的。由于MFC對象的1些函數(shù)都與TLS有關(guān)聯(lián),  所以有些調(diào)用會出錯。如UpdateData(),最好通過句柄發(fā)消息來完成相應(yīng)的功能。

生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對您的學(xué)習(xí)有所幫助,可以手機掃描二維碼進(jìn)行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: 无人精品乱码一区二区三区 | 噜噜噜在线视频免费观看 | 99久久成人 | 亚洲爽爽网 | 一级毛片一级毛片一级毛片aa | 手机在线观看免费视频 | 日韩手机视频 | 色费女人18毛片a级视频在线 | 欲色网站| 五月国产综合视频在线观看 | 亚洲爱v | 中文字幕精品一区二区精品 | 欧美亚洲天堂网 | 欧美一二三区 | 亚洲一区二区色 | 波多野衣结在线精品二区 | 亚洲14p| 男女羞羞视频网站 | 色影音| 久久久影院亚洲精品 | 九九精品成人免费国产片 | 呦女亚洲一区精品 | 一级做a爰性视频 | 一区二区三区成人 | 最近中文字幕高清1 | 欧美日韩一区二区三区视频播 | 韩国午夜理伦三级网 | 成人免费视频在线看 | 激情图片小说区 | 国产一区三区二区中文在线 | 国产成人一级片 | 69av在线| 性的小视频在线观看免费 | 性欧美video另类hd高清 | 日本一区2区 | 波多野结衣国产一区二区三区 | 欧美一级片手机在线观看 | 在线观看一级毛片免费 | 丁香综合五月 | 国产在线拍国产拍拍偷 | 琪琪see色原网中文 琪琪理论影院2018中文版 |