標籤:windows 線程同步 鎖 共用鎖定 排 windows c 效能
眾所周知,windows平台上實現線程同步,或者說資源的加鎖與解鎖的方法有核心事件、臨界區、互斥量、訊號量,甚至interlocked系列函數等多種手段。但是在日常的編程中,我們使用這些手段對 “多個線程同時對同一個資源進行讀寫”的時候,在讀寫之前先要對資源假鎖,讀寫完之後要對資源解鎖。
設想這樣一種情況,有一個ftp伺服器,每天有很頻繁的對這個ftp服務的檔案進行下載,但是幾乎好幾天才會對這些檔案進行更新。在我們每一次對檔案下載的時候,讀取檔案的時候都要對檔案進行加鎖,以保證同時沒有其他人對檔案進行寫入。但是這些加鎖的行為,在99%的時候都是不會有人同時寫入檔案的,只有1%的情況下會有人同時也要寫入檔案。這樣的話,我們多鎖就大大的浪費了,而且你在加鎖的同時,別人即使也只是讀取檔案,也需要等你先解鎖。
解決這個問題的辦法是,對檔案的讀取設定共用鎖定,多個線程可以同時讀檔案,不會互相阻塞。再設定獨佔鎖,當要對檔案進行寫入的時候,加上獨佔鎖,這樣別的線程此時不能讀也不能寫。
windows提供了一個稱為slim 的共用/獨佔鎖來解決這個問題。但是呢,slim只在vista和window server 2008才支援。在之前的版本上沒有支援。於是,我就w利用現有的線程同步手段,來類比達到slim這一個共用/獨佔鎖的功能,代碼封裝如下:
</pre><pre name="code" class="cpp">//共用和獨佔鎖(讀不鎖,寫鎖),適用於資源的讀的頻率比寫的頻率高的情況//共用鎖定: 大家都可以同時讀,但是不能寫。//獨佔鎖: 就是只有一個人獨佔使用,不管是讀還是寫//規定:acquire和release必須成對出現,不支援嵌套以及互相嵌套//缺點:需要對加鎖過程本身進行臨界區控制,會帶來細微的效能損失#ifdef __cplusplusextern "C" {#endifstruct SELock //Shared & Exclusive lock{ RTL_CRITICAL_SECTION sec_shared,sec_exclusive; //對加鎖代碼本身進行臨界區控制 HANDLE exclusive_evt; HANDLE shared_evt; volatile long shared_count;};//初始化一個SE鎖_inline void InitializeSELock(SELock *lock){ InitializeCriticalSection(&lock->sec_shared); InitializeCriticalSection(&lock->sec_exclusive); lock->exclusive_evt = CreateEventW(NULL,TRUE,TRUE,NULL); lock->shared_evt = CreateEventW(NULL,TRUE,TRUE,NULL); lock->shared_count = 0;}//清理一個SE鎖_inline void DeleteSELock(SELock *lock){ DeleteCriticalSection(&lock->sec_shared); DeleteCriticalSection(&lock->sec_exclusive); CloseHandle(lock->exclusive_evt); CloseHandle(lock->shared_evt); lock->shared_count = 0;}//請求共用鎖定,用於讀_inline void AcquireSELockShared(SELock *lock){ EnterCriticalSection(&lock->sec_exclusive); EnterCriticalSection(&lock->sec_shared); WaitForSingleObject(lock->exclusive_evt,INFINITE); //等待獨佔鎖 ++lock->shared_count; if(lock->shared_count) ResetEvent(lock->shared_evt); //開啟共用鎖定 LeaveCriticalSection(&lock->sec_shared); LeaveCriticalSection(&lock->sec_exclusive);}//釋放共用鎖定_inline void ReleaseSELockShared(SELock *lock){ EnterCriticalSection(&lock->sec_shared); --lock->shared_count; if(!lock->shared_count) SetEvent(lock->shared_evt); //關閉共用鎖定 LeaveCriticalSection(&lock->sec_shared); }//請求獨佔鎖_inline void AcquireSELockExclusive(SELock *lock){ EnterCriticalSection(&lock->sec_exclusive); WaitForSingleObject(lock->exclusive_evt,INFINITE); //等待獨佔鎖 WaitForSingleObject(lock->shared_evt,INFINITE); //等待共用鎖定 ResetEvent(lock->exclusive_evt); //開啟獨佔鎖 LeaveCriticalSection(&lock->sec_exclusive);}//釋放獨佔鎖_inline void ReleaseSELockExclusive(SELock *lock){ SetEvent(lock->exclusive_evt); //關閉獨佔鎖}#ifdef __cplusplus}#endif