• <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>
            asm, c, c++ are my all
            -- Core In Computer
            posts - 139,  comments - 123,  trackbacks - 0
            上一篇中我介紹了一種通過(guò)封閉Critical Section對(duì)象而方便的使用互斥鎖的方式,文中所有的例子是兩個(gè)線程對(duì)同一數(shù)據(jù)一讀一寫,因此需要讓它們?cè)谶@里互斥,不能同時(shí)訪問(wèn)。而在實(shí)際情況中可能會(huì)有更復(fù)雜的情況出現(xiàn),就是多個(gè)線程訪問(wèn)同一數(shù)據(jù),一部分是讀,一部分是寫。我們知道只有讀-寫或?qū)?寫同時(shí)進(jìn)行時(shí)可能會(huì)出現(xiàn)問(wèn)題,而讀-讀則可以同時(shí)進(jìn)行,因?yàn)樗鼈儾粫?huì)對(duì)數(shù)據(jù)進(jìn)行修改,所以也有必要在C++中封裝一種方便的允許讀-讀并發(fā)、讀-寫與寫-寫互斥的鎖。要實(shí)現(xiàn)這種鎖,使用臨界區(qū)就很困難了,不如改用內(nèi)核對(duì)象,這里我使用的是互斥量(Mutex)。

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

            與WaitForMultipleObjects類似的還有一個(gè)函數(shù)WaitForSingleObject,它的功能比較簡(jiǎn)單,只針對(duì)單一個(gè)對(duì)象,而WaitForMultipleObjects可以同時(shí)等待多個(gè)對(duì)象,并且可以設(shè)置是否等待所有對(duì)象。

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

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

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

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

            ??????? {
            ??????????????
            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()????????????????????????????
            // 構(gòu)造函數(shù),初始化每個(gè)互斥量

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

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

            }
            ;
            而相應(yīng)的鎖類也會(huì)稍復(fù)雜一些:
            class ?RWLock
            {
            ???????
            bool ?lockSuccess;???????????????? // 因?yàn)橛锌赡艹瑫r(shí),需要保存是否等待成功

            ??????? int ?readLockHandleIndex;?????? // 對(duì)于讀鎖,需要知道獲得的是哪個(gè)互斥量
            ???????_RWLockBase * ?_pObj;????????? // 目標(biāo)對(duì)象基類指針
            public :
            ???????
            // 這里通過(guò)第二個(gè)參數(shù)決定是加讀鎖還是寫鎖,第三個(gè)參數(shù)為超時(shí)的時(shí)間

            ???????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就是數(shù)組下標(biāo)
            ????????????????????????????readLockHandleIndex? = ?retval? - ?WAIT_OBJECT_0;
            ????????????????????????????lockSuccess?
            =
            ?TRUE;
            ?????????????????????}

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

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

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

            ???????}

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

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

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

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

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

            ???????
            else ????????????????????????????????????? // 加鎖超時(shí),則顯示超時(shí)信息
            ??????????????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個(gè)線程,5個(gè)讀5個(gè)寫。從RWLockBase類繼承時(shí)我們使用了默認(rèn)的模板參數(shù),所以最多同時(shí)允許3個(gè)讀線程。程序的運(yùn)行結(jié)果如下:
            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
            前三行三個(gè)讀線程取得讀鎖,之后等一秒(第4-8行),三個(gè)讀線程都結(jié)束了,并且余下的兩個(gè)讀線程取得讀鎖,雖然這時(shí)剩下了一個(gè)互斥量沒有使用,但因?yàn)槠渌木€程都請(qǐng)求加寫鎖,寫鎖與其他所有線程互斥,所以還不能取得寫鎖。再過(guò)一秒(第9-11行),后來(lái)的兩個(gè)取得讀鎖的線程也結(jié)束了,則第一個(gè)寫線程取得寫鎖。600毫秒之后(第12-13行)第一個(gè)寫線程結(jié)束,第二個(gè)寫線程開始。400毫秒之后(第14-16行)余下的三個(gè)寫線程都超時(shí)了,再后第二個(gè)寫線程也結(jié)束了。
            posted on 2006-10-19 14:35 Jerry Cat 閱讀(1503) 評(píng)論(1)  編輯 收藏 引用

            FeedBack:
            # re: Win32環(huán)境下兩種用于C++的線程同步類(下)
            2006-10-19 14:35 | Jerry Cat
            不知here有沒有南京的網(wǎng)友, 我以前南京的一個(gè)同學(xué)趙小姐要我?guī)兔Πl(fā)個(gè)租房消息, 某雖不懂但老同學(xué)的事也不好推, 將就如下:

            現(xiàn)有位于南京市江寧區(qū)"武夷花園"小區(qū)的三室一廳住房一套, 水,電,氣齊全, 室內(nèi)有熱水器, 電視機(jī)及床, 衣柜等簡(jiǎn)單家具. 整租, 與人合租均可. 聯(lián)系人: 趙小姐 電話:025-83909202  回復(fù)  更多評(píng)論
              

            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理



            <2006年4月>
            2627282930311
            2345678
            9101112131415
            16171819202122
            23242526272829
            30123456

            常用鏈接

            留言簿(7)

            隨筆檔案

            最新隨筆

            搜索

            •  

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            超级碰久久免费公开视频| 日本免费一区二区久久人人澡| 久久中文字幕人妻熟av女| 久久久国产99久久国产一| 亚洲精品乱码久久久久久中文字幕| 无码人妻久久一区二区三区 | 品成人欧美大片久久国产欧美...| 国产无套内射久久久国产| 亚洲人成无码久久电影网站| 国色天香久久久久久久小说 | 亚洲人AV永久一区二区三区久久| 伊人久久大香线蕉精品不卡 | 久久ww精品w免费人成| 2021国产成人精品久久| 麻豆精品久久久久久久99蜜桃| 熟妇人妻久久中文字幕| 国产成人香蕉久久久久| 亚洲精品乱码久久久久久中文字幕| 国产一区二区三区久久精品| 天天综合久久一二三区| 国产成人久久精品一区二区三区 | 久久狠狠一本精品综合网| 综合久久一区二区三区| 国产精品久久久久久一区二区三区| 久久久久久国产精品无码下载 | 国产精品99久久不卡| 欧美一区二区三区久久综合 | 7777精品久久久大香线蕉| 久久91这里精品国产2020| 漂亮人妻被黑人久久精品| 免费精品久久久久久中文字幕| 久久91精品国产91久久麻豆| 色天使久久综合网天天| 久久精品亚洲欧美日韩久久| 精品久久久久久国产91| 77777亚洲午夜久久多喷| 免费一级欧美大片久久网 | 久久人人爽人人爽人人AV东京热| 亚洲欧美一级久久精品| 99久久久久| 9191精品国产免费久久|