青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

asm, c, c++ are my all
-- Core In Computer
posts - 139,  comments - 123,  trackbacks - 0
上一篇中我介紹了一種通過封閉Critical Section對象而方便的使用互斥鎖的方式,文中所有的例子是兩個線程對同一數據一讀一寫,因此需要讓它們在這里互斥,不能同時訪問。而在實際情況中可能會有更復雜的情況出現,就是多個線程訪問同一數據,一部分是讀,一部分是寫。我們知道只有讀-寫或寫-寫同時進行時可能會出現問題,而讀-讀則可以同時進行,因為它們不會對數據進行修改,所以也有必要在C++中封裝一種方便的允許讀-讀并發、讀-寫與寫-寫互斥的鎖。要實現這種鎖,使用臨界區就很困難了,不如改用內核對象,這里我使用的是互斥量(Mutex)。

總體的結構與上一篇中的類似,都是寫出一個對鎖進行封裝的基類,再寫一個用于調用加、解鎖函數的類,通過對第二個類的生命周期的管理實現加鎖和解鎖。這里涉及到兩個新問題,一是加鎖、解鎖動作都有兩種,一種是加/解讀鎖,一種是加/解寫鎖;二是為了允許讀-讀并發,這里只聲明一個Mutex是不夠的,必須要聲明多個Mutex,而且有多少個Mutex就同時允許多少個讀線程并發,之所以這么說,是因為我們要使用的API函數是WaitForMultipleObjects。
WaitForMultipleObjects函數的功能就是等待對象狀態被設置,MSDN中對它的說明為:
Waits until one or all of the specified objects are in the signaled state or the time-out interval elapses.
這是個很好用的函數,我們可以用它來等待某個或某幾個對象,并且允許設置超時時間,等待成功時與超時時返回的值是不同的。如果返回的值比WAIT_ABANDONED小則表示等待成功。“等待成功”對于不同類型的內核對象有不同的意義,例如對于進程或線程對象,等待成功就表示進程或線程執行結束了;對于互斥量對象,則表示此對象現在不被任何其他線程擁有,并且一旦等待成功,當前線程即擁有了此互斥量,其他線程則不能同時擁有,直接調用ReleaseMutex函數主動釋放互斥量。

與WaitForMultipleObjects類似的還有一個函數WaitForSingleObject,它的功能比較簡單,只針對單一個對象,而WaitForMultipleObjects可以同時等待多個對象,并且可以設置是否等待所有對象。

上一篇文章中用的InstanceLockBase類里面封裝了一個Critical Section對象,這里則要封裝一組Mutex的Handle,那么這一組是多少個呢?它應該由使用此類的程序中定義,例如可以用動態數組的方法:
// 基類:
??????? class ?RWLockBase? // 表示Read/Write?Lock
??????? {
??????????????HANDLE
*
?handles;
???????
protected
:
??????????????RWLockBase(
int ?handleCount)? {?handles? = ? new ?HANDLE[handleCount];?}

??????????????…
???????}
;
// 子類:

??????? class ?MyClass:? public ?RWLockBase??????
???????
{
??????????????MyClass():?RWLockBase(
3 )? {}

??????????????…
???????}
;
這確實是個不錯的辦法,通過在子類構造函數的初始化段中調用基類構造函數并傳參,使得這個動態數組得以正確初始化,不過這樣看著不太爽,子類必須兩次出現“RWLockBase”一詞,能不能像InstanceLockBase那樣只要繼承了就好呢?答案是肯定的,只要用C++模板即可:
???????template? < int ?maxReadCount >
???????
class ?RWLockBase
???????
{
??????????????HANDLE?handles[maxReadCount];
??????????????…
???????}
;
使用模板附帶這么一個好處,因為模板參數是在編譯期可以確定的,所以無需再用動態數組,直接在棧上分配即可。而使用模板引出一個新問題,就是相應的Lock類(RWLock)在構造時傳的對象指針時的類型聲明,直接寫成RWLock(RWLockBase* pObj)肯定是不行的,因為必須指定模板參數,并且其值還必須與聲明RWLockBase時所指定的值一致才行,從而客戶端代碼就必須兩次指定模板參數值,不爽!解決的辦法也是有一個,就是把RWLockBase變成夾層類,為它再聲明一個基類,讓RWLock接收的是基類指針,并把Lock、Unlock等函數放在基類中,聲明為純虛函數,實現寫在夾層類中:
class ?_RWLockBase
{
???????friend?
class
?RWLock;
protected
:
???????
virtual ?DWORD?ReadLock( int ?timeout)? = ? 0
;
???????
virtual ? void ?ReadUnlock( int ?handleIndex)? = ? 0
;
???????
virtual ?DWORD?WriteLock( int ?timeout)? = ? 0
;
???????
virtual ? void ?WriteUnlock()? = ? 0
;
}
;
模板類RWLockBase從_RWLockBase繼承,并對四個函數寫出實現:
template? < int ?maxReadCount? = ? 3 > ???????? // 這里給一個缺省參數,盡量減少客戶端代碼量
class ?RWLockBase:? public ?_RWLockBase
{
???????HANDLE?handles[maxReadCount];
???????DWORD?ReadLock(
int ?timeout)??? // 加讀鎖,只要等到一個互斥量返回即可

??????? {
??????????????
return
?::WaitForMultipleObjects(maxReadCount,?handles,?FALSE,?timeout);
???????}

???????
void ?ReadUnlock( int ?handleIndex)? // 解讀鎖,釋放已獲得的互斥量
??????? {
??????????????::ReleaseMutex(handles[handleIndex]);
???????}

???????DWORD?WriteLock(
int ?timeout)??? // 加寫鎖,等到所有互斥量,從而與其他所有線程互斥
??????? {
??????????????
return
?::WaitForMultipleObjects(maxReadCount,?handles,?TRUE,?timeout);
???????}

???????
void ?WriteUnlock()?????????????????????? // 解寫鎖,釋放所有的互斥量
??????? {
??????????????
for ( int ?i? = ? 0 ;?i? < ?maxReadCount;?i ++
)
?????????????????????::ReleaseMutex(handles[i]);
???????}

protected :
???????RWLockBase()????????????????????????????
// 構造函數,初始化每個互斥量

??????? {
??????????????
for ( int ?i? = ? 0 ;?i? < ?maxReadCount;?i ++
)
?????????????????????handles[i]?
= ?::CreateMutex( 0 ,?FALSE,? 0
);
???????}

???????
~ RWLockBase()?????????????????????????? // 析構函數,銷毀對象
??????? {
??????????????
for ( int ?i? = ? 0 ;?i? < ?maxReadCount;?i ++
)
?????????????????????::CloseHandle(handles[i]);
???????}

}
;
而相應的鎖類也會稍復雜一些:
class ?RWLock
{
???????
bool ?lockSuccess;???????????????? // 因為有可能超時,需要保存是否等待成功

??????? int ?readLockHandleIndex;?????? // 對于讀鎖,需要知道獲得的是哪個互斥量
???????_RWLockBase * ?_pObj;????????? // 目標對象基類指針
public :
???????
// 這里通過第二個參數決定是加讀鎖還是寫鎖,第三個參數為超時的時間

???????RWLock(_RWLockBase * ?pObj,? bool ?readLock? = ? true ,? int ?timeout? = ? 3000 )
???????
{
??????????????_pObj?
=
?pObj;
??????????????lockSuccess?
=
?FALSE;
??????????????readLockHandleIndex?
= ? - 1
;
??????????????
if (NULL? ==
?_pObj)
?????????????????????
return
;
?
??????????????
if (readLock)?????????? // 讀鎖

?????????????? {
?????????????????????DWORD?retval?
= ?_pObj ->
ReadLock(timeout);
?????????????????????
if (retval? < ?WAIT_ABANDONED)? // 返回值小于WAIT_ABANDONED表示成功

????????????????????? {??????????????????????????????????????????????? // 其值減WAIT_OBJECT_0就是數組下標
????????????????????????????readLockHandleIndex? = ?retval? - ?WAIT_OBJECT_0;
????????????????????????????lockSuccess?
=
?TRUE;
?????????????????????}

??????????????}

??????????????
else
??????????????
{
?????????????????????DWORD?retval?
= ?_pObj ->
WriteLock(timeout);
?????????????????????
if (retval? < ?WAIT_ABANDONED)? // 寫鎖時獲得了所有互斥量,無需保存下標

????????????????????????????lockSuccess? = ?TRUE;
??????????????}

???????}

???????
~ RWLock()
???????
{
??????????????
if (NULL? ==
?_pObj)
?????????????????????
return
;
??????????????
if (readLockHandleIndex? > ? - 1
)
?????????????????????_pObj
->
ReadUnlock(readLockHandleIndex);
??????????????
else

?????????????????????_pObj
-> WriteUnlock();
???????}

???????
bool ?IsLockSuccess()? const ? {? return ?lockSuccess;?}
}
;
?
這樣一來,讀/寫鎖的類也就完成了,使用時與InstanceLock類似:
1 被鎖對象從RWLockBase<>類繼承
2 需要加讀鎖時,聲明一個RWLock實例,并指出要加的是讀鎖
3 需要加寫鎖時,聲明一個RWLock實例,并指出要加的是寫鎖
?
這里還是要多說兩句,雖然使用純虛函數結合模板類,使得客戶端代碼量減到最少,但性能上有一些影響,因為聲明了虛函數,則實例中必然存在4個字節的VPTR,調用虛函數時則要查找VTABLE,空間和時間上都有微小的犧牲。而如果不使用模板類,則沒有虛函數的代價,但也有犧牲:不使用模板類則需要使用動態數組,動態數組本身需要程序運行時在堆上分配,這也需要時間;指向動態數組的指針也需要占用內存,所以空間上的開鎖是一樣的,時間上雖然動態分配內存需要的時間應該比虛函數的調用要慢一點,但初始化只需要一次,總體來說也是值得的。所以最終要使用哪一種,就看具體需要了。
?
這里也給出一個實驗。這里所用的被鎖類也上一篇類似,簡單的從RWLockBase類繼承:
class ?MyClass2:? public ?RWLockBase <>
{} ;
MyClass2?mc2;
看看兩個線程函數:
// 讀線程
DWORD?CALLBACK?ReadThreadProc(LPVOID?param)
{
???????
int ?i? = ?( int
)param;
???????RWLock?
lock ( & mc2);?????????? // 加讀鎖

??????? if ( lock .IsLockSuccess())????????????? // 如果加鎖成功
??????? {
??????????????Say(
" read?thread?%d?started " ,?i);??? // 為了代碼短一些,假設Say函數有這種能力

??????????????Sleep( 1000 );
??????????????Say(
" read?thread?%d?ended "
,?i);
???????}

???????
else ????????????????????????????????????? // 加鎖超時,則顯示超時信息
??????????????Say( " read?thread?%d?timeout " ,?i);
???????
return ? 0
;
}

// 寫線程
DWORD?CALLBACK?WriteThreadProc(LPVOID?param)
{
???????
int ?i? = ?( int
)param;
???????RWLock?
lock ( & mc2,? false );? // 加寫鎖。

??????? if ( lock .IsLockSuccess())
???????
{
??????????????Say(
" write?thread?%d?started "
,?i);
??????????????Sleep(
600
);
??????????????Say(
" write?thread?%d?ended "
,?i);
???????}

???????
else
??????????????Say(
" write?thread?%d?timeout " ,?i);
???????
return ? 0
;
}
?
主線程:
??????? int ?i;
???????
for (i? = ? 0 ;?i? < ? 5 ;?i ++
)
??????????????::CreateThread(
0 ,? 0 ,?ReadThreadProc,?(LPVOID)i,? 0 ,? 0
);
???????
for (i? = ? 0 ;?i? < ? 5 ;?i ++
)
??????????????::CreateThread(
0 ,? 0 ,?WriteThreadProc,?(LPVOID)i,? 0 ,? 0 );
程序共開10個線程,5個讀5個寫。從RWLockBase類繼承時我們使用了默認的模板參數,所以最多同時允許3個讀線程。程序的運行結果如下:
001 [15:07:28.484]read thread 0 started
002 [15:07:28.484]read thread 1 started
003 [15:07:28.484]read thread 2 started
004 [15:07:29.484]read thread 0 ended
005 [15:07:29.484]read thread 3 started
006 [15:07:29.484]read thread 1 ended
007 [15:07:29.484]read thread 4 started
008 [15:07:29.484]read thread 2 ended
009 [15:07:30.484]read thread 3 ended
010 [15:07:30.484]read thread 4 ended
011 [15:07:30.484]write thread 0 started
012 [15:07:31.078]write thread 0 ended
013 [15:07:31.078]write thread 1 started
014 [15:07:31.484]write thread 2 timeout
015 [15:07:31.484]write thread 3 timeout
016 [15:07:31.484]write thread 4 timeout
017 [15:07:31.687]write thread 1 ended
前三行三個讀線程取得讀鎖,之后等一秒(第4-8行),三個讀線程都結束了,并且余下的兩個讀線程取得讀鎖,雖然這時剩下了一個互斥量沒有使用,但因為其他的線程都請求加寫鎖,寫鎖與其他所有線程互斥,所以還不能取得寫鎖。再過一秒(第9-11行),后來的兩個取得讀鎖的線程也結束了,則第一個寫線程取得寫鎖。600毫秒之后(第12-13行)第一個寫線程結束,第二個寫線程開始。400毫秒之后(第14-16行)余下的三個寫線程都超時了,再后第二個寫線程也結束了。
posted on 2006-10-19 14:35 Jerry Cat 閱讀(1514) 評論(1)  編輯 收藏 引用

FeedBack:
# re: Win32環境下兩種用于C++的線程同步類(下)
2006-10-19 14:35 | Jerry Cat
不知here有沒有南京的網友, 我以前南京的一個同學趙小姐要我幫忙發個租房消息, 某雖不懂但老同學的事也不好推, 將就如下:

現有位于南京市江寧區"武夷花園"小區的三室一廳住房一套, 水,電,氣齊全, 室內有熱水器, 電視機及床, 衣柜等簡單家具. 整租, 與人合租均可. 聯系人: 趙小姐 電話:025-83909202  回復  更多評論
  

<2025年9月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

常用鏈接

留言簿(7)

隨筆檔案

最新隨筆

搜索

  •  

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            国产美女精品人人做人人爽| 亚洲欧美日韩国产精品| 亚洲一区二区免费看| 亚洲人成人一区二区三区| 亚洲国内高清视频| 99国产精品久久久久久久久久 | 亚洲精品日韩精品| 91久久夜色精品国产九色| 亚洲第一久久影院| 一本久久知道综合久久| 午夜视频在线观看一区二区| 久久乐国产精品| 欧美精品一区二区三区很污很色的 | 美女尤物久久精品| 亚洲精品乱码久久久久| 亚洲在线国产日韩欧美| 久热精品视频在线观看| 欧美三日本三级少妇三2023| 精品av久久久久电影| 亚洲夜晚福利在线观看| 久久综合九色九九| 夜夜嗨av一区二区三区| 乱码第一页成人| 国产精品入口66mio| 亚洲国产高潮在线观看| 亚洲一线二线三线久久久| 免费视频久久| 亚洲欧美影院| 欧美日韩在线精品| 亚洲国产精品一区二区三区| 欧美亚洲免费高清在线观看| 亚洲国产欧美不卡在线观看| 欧美一区二区三区四区在线观看| 欧美日本久久| 亚洲国产精品毛片| 久久亚洲不卡| 香港久久久电影| 国产精品免费看| 亚洲视屏一区| 亚洲精品久久久久久一区二区| 久久久久久精| 国产一区二区三区观看| 亚洲欧美亚洲| 一区二区三区国产在线| 欧美激情一区二区三区在线视频| 激情av一区| 久久这里有精品视频| 亚洲欧美激情视频在线观看一区二区三区| 欧美日本一区| 日韩亚洲在线观看| 亚洲国产精品一区二区第四页av| 久久免费高清| **性色生活片久久毛片| 久久在线精品| 国产精品久久久久久久久免费樱桃| 久久精品视频网| 国产自产高清不卡| 亚洲精品国产精品久久清纯直播 | 亚洲——在线| 国产精品网站在线观看| 亚洲欧美综合一区| 亚洲午夜精品国产| 国产欧美精品xxxx另类| 欧美一区二区三区啪啪| 性欧美暴力猛交另类hd| 国产一区二区精品丝袜| 久久久久成人网| 久久国产成人| 亚洲韩国日本中文字幕| 亚洲品质自拍| 国产精品久久久久久久久果冻传媒| 亚洲一级免费视频| 亚洲一区二区精品视频| 国产一级精品aaaaa看| 美女精品在线观看| 欧美精品九九99久久| 亚洲一区二区精品| 西瓜成人精品人成网站| 亚洲国产va精品久久久不卡综合| 亚洲电影视频在线| 欧美三区不卡| 久久免费一区| 模特精品在线| 亚洲欧美精品在线| 久久激情久久| 亚洲一区二区动漫| 久久天天躁狠狠躁夜夜av| 日韩亚洲精品视频| 午夜亚洲影视| 99亚洲伊人久久精品影院红桃| 亚洲性线免费观看视频成熟| 在线播放日韩专区| 国产精品99久久99久久久二8| 国产一区二区三区在线观看精品| 最近看过的日韩成人| 国产午夜精品视频| 亚洲免费成人av| 韩日午夜在线资源一区二区| 亚洲精品一区二区在线| 国产一区二区精品久久99| 亚洲乱亚洲高清| 极品裸体白嫩激情啪啪国产精品| 免费永久网站黄欧美| 亚洲宅男天堂在线观看无病毒| 欧美中在线观看| 亚洲制服av| 麻豆精品传媒视频| 久久精品日产第一区二区三区| 欧美激情麻豆| 巨乳诱惑日韩免费av| 国产精品久久久久毛片大屁完整版| 欧美jizzhd精品欧美巨大免费| 国产精品久久久久久久久久妞妞| 亚洲高清在线观看一区| 国产自产在线视频一区| 亚洲一区二区精品在线| 一区二区三区.www| 免费人成网站在线观看欧美高清 | 中文亚洲视频在线| 久久免费观看视频| 久久精品国产亚洲a| 国产精品久久久久久久久久免费 | 亚洲作爱视频| 99精品欧美一区二区三区| 久久深夜福利| 久久一区精品| 韩日精品在线| 久久久水蜜桃| 欧美高清在线一区| 亚洲国产成人精品久久久国产成人一区| 亚洲制服av| 欧美一区二区三区四区夜夜大片| 国产精品成人一区| 亚洲网站视频| 欧美在线视频免费播放| 国产乱码精品一区二区三区不卡| 一区二区三区高清不卡| 亚洲欧美日韩成人高清在线一区| 欧美日韩在线播放| 一区二区国产在线观看| 午夜亚洲影视| 国产一区二区三区直播精品电影 | 亚洲福利精品| 欧美福利精品| 日韩一级大片在线| 亚洲男人的天堂在线aⅴ视频| 国产精品久久久久久久久搜平片| 亚洲一区精品在线| 久久国产一二区| 亚洲高清在线| 欧美色精品天天在线观看视频| 这里只有精品丝袜| 欧美一区二区三区四区在线观看地址 | aa亚洲婷婷| 亚洲精品免费在线| 欧美乱妇高清无乱码| 亚洲人成网站在线观看播放| 一区二区三区欧美激情| 国产日韩亚洲欧美精品| 久久九九免费视频| 亚洲日本中文| 久久久久久久久久久久久9999| 最新国产成人在线观看| 国产精品激情| 欧美黑人国产人伦爽爽爽| 亚洲图片在线观看| 欧美成人中文| 久久成人精品无人区| 日韩视频一区二区三区| 国产欧美一二三区| 欧美激情一区二区在线| 亚洲欧美综合| 亚洲美女区一区| 麻豆国产va免费精品高清在线| 国产精品99久久久久久久vr| 激情成人综合| 国产精品免费网站| 欧美激情精品久久久久| 久久国产精品高清| 亚洲欧美日韩一区二区三区在线| 亚洲人永久免费| 蜜臀91精品一区二区三区| 亚洲尤物精选| 一区二区三区.www| 亚洲国产欧美一区二区三区久久| 国产精品―色哟哟| 欧美日韩理论| 噜噜噜91成人网| 久久国产精品72免费观看| 亚洲视频狠狠| 一本色道久久综合亚洲精品不卡| 亚洲国产精品久久久久秋霞影院 | 久久成人亚洲| 亚洲综合日韩在线| 亚洲精品一区在线观看| 欧美高潮视频| 蜜臀a∨国产成人精品| 欧美综合国产| 欧美在线free| 欧美尤物一区|