Win32多執行緒程式設計之執行緒通訊 (三)

2021-04-21 08:03:28 字數 3225 閱讀 1391

訊號量

訊號量是維護0到指定最大值之間的同步物件。訊號量狀態在其計數大於0時是有訊號的,而其計數是0時是無訊號的。訊號量物件在控制上可以支援有限數量共享資源的訪問。

訊號量的特點和用途可用下列幾句話定義:

(1)如果當前資源的數量大於0,則訊號量有效;

(2)如果當前資源數量是0,則訊號量無效;

(3)系統決不允許當前資源的數量為負值;

(4)當前資源數量決不能大於最大資源數量。

建立訊號量

handle createsemaphore (

psecurity_attribute psa,

long linitialcount, //開始時可供使用的資源數

long lmaximumcount, //最大資源數

pctstr pszname);

釋放訊號量

通過呼叫releasesemaphore函式,執行緒就能夠對信標的當前資源數量進行遞增,該函式原型為:

bool winapi releasesemaphore(

handle hsemaphore,

long lreleasecount, //訊號量的當前資源數增加lreleasecount

lplong lppreviouscount);

開啟訊號量

和其他核心物件一樣,訊號量也可以通過名字跨程序訪問,開啟訊號量的api為:

handle opensemaphore (

dword fdwaccess

,bool binherithandle,

pctstr pszname);

互鎖訪問

當必須以原子操作方式來修改單個值時,互鎖訪問函式是相當有用的。所謂原子訪問,是指執行緒在訪問資源時能夠確保所有其他執行緒都不在同一時間內訪問相同的資源。

請看下列**:

int globalvar = 0;

dword winapi threadfunc1(lpvoid n)

dword winapi threadfunc2(lpvoid n)

執行threadfunc1和threadfunc2執行緒,結果是不可預料的,因為globalvar++並不對應著一條機器指令,我們看看globalvar++的反

彙編**:

00401038 mov eax,[globalvar (0042d3f0)]

0040103d add eax,1

00401040 mov [globalvar (0042d3f0)],eax

在"mov eax,[globalvar (0042d3f0)]" 指令與"add eax,1" 指令以及"add eax,1" 指令與"mov [globalvar (0042d3f0)],eax"指令之間都可能發生執行緒切換,使得程式的執行後globalvar的結果不能確定。我們可以使用interlocked

exchange

add函式解決這個問題:

int globalvar = 0;

dword winapi threadfunc1(lpvoid n)

dword winapi threadfunc2(lpvoid n)

interlockedexchangeadd保證對變數globalvar的訪問具有"原子性"。互鎖訪問的控制速度非常快,呼叫乙個互鎖函式的cpu週期通常小於50,不需要進行使用者方式與核心方式的切換(該切換通常需要執行1000個cpu週期)。

互鎖訪問函式的缺點在於其只能對單一變數進行原子訪問,如果要訪問的資源比較複雜,仍要使用臨界區或互斥。

可等待定時器

可等待定時器是在某個時間或按規定的間隔時間發出自己的訊號通知的核心物件。它們通常用來在某個時間執行某個操作。

建立可等待定時器

handle createwaitabletimer(

psecurity_attrisutes psa,

bool fmanualreset,//人工重置或自動重置定時器

pctstr pszname);

設定可等待定時器

可等待定時器物件在非啟用狀態下被建立,程式設計師應呼叫 setwaitabletimer函式來界定定時器在何時被啟用:

bool setwaitabletimer(

handle htimer, //要設定的定時器

const large_integer *pduetime, //指明定時器第一次啟用的時間

long lperiod, //指明此後定時器應該間隔多長時間啟用一次

ptimerapcroutine pfncompletionroutine,

pvoid pvargtocompletionroutine,

bool fresume);

取消可等待定時器

bool cancel waitabletimer(

handle htimer //要取消的定時器);

開啟可等待定時器

作為一種核心物件,waitabletimer也可以被其他程序以名字開啟:

handle openwaitabletimer (

dword fdwaccess,

bool binherithandle,

pctstr pszname);

例項

下面給出的乙個程式可能發生死鎖現象:

#include .h>

#include

critical_section cs1, cs2;

long winapi threadfn(long);

main()

;return (0);

}long winapi threadfn(long lparam);}

執行這個程式,在中途一旦發生這樣的輸出:

執行緒1占用臨界區1

執行緒2占用臨界區2 或

執行緒2占用臨界區2

執行緒1占用臨界區1 或

執行緒1占用臨界區2

執行緒2占用臨界區1 或

執行緒2占用臨界區1

執行緒1占用臨界區2

程式就"死"掉了,再也執行不下去。因為這樣的輸出,意味著兩個執行緒相互等待對方釋放臨界區,也即出現了死鎖。

如果我們將執行緒2的控制函式改為:

long winapi threadfn(long lparam);}

再次執行程式,死鎖被消除,程式不再擋掉。這是因為我們改變了執行緒2中獲得臨界區1、2的順序,消除了執行緒1、2相互等待資源的可能性。

由此我們得出結論,在使用執行緒間的同步機制時,要特別留心死鎖的發生。

win32多執行緒程式設計

使用3個執行緒完成6個任務,工作的執行是靠呼叫sleep 來模擬,時間長度是隨機給予的,只要乙個執行緒結束,就會有另乙個執行緒被產生。taskques.cpp 定義控制台應用程式的入口點。include stdafx.h include include include define win32 le...

Win32 多執行緒程式設計

程序和執行緒都是作業系統的概念 程序是應用程式的執行例項 每個程序是由私有的虛擬位址空間 資料和其它各種系統資源組成 程序在執行過程中建立的資源隨著程序的終止而被銷毀 所使用的系統資源在程序終止時被釋放或關閉 執行緒是程序內部的乙個執行單元 系統建立好程序後 實際上就啟動執行了該程序的主執行執行緒 ...

Win32多執行緒之概述

win32多執行緒之概述 多執行緒在剛開始工作時也沒怎麼用,只是有時介面卡住了 一拖動程式主介面介面就會出現白色區域,久久不能消失,慢慢的明白主介面使用主線程,在單一執行緒通道中,乙個任務沒有完成,當前的所有工 作都將被鎖定,拖動介面會產生wm paint訊息,由於主線程被鎖定那麼這個訊息將不被程式...