Windows apiベースの共有ロック/パーソナルロック


Windowsプラットフォーム上でスレッド同期を実現する方法、あるいはリソースのロックとロック解除の方法には、カーネルイベント、臨界領域、反発量、信号量、さらにはinterlockedシリーズ関数など多くの手段が知られている.しかし、日常のプログラミングでは、これらの手段を用いて「複数のスレッドが同時に同じリソースを読み書きする」場合、読み書きの前にリソースの偽ロックを行い、読み書きが終わった後にリソースをロック解除します.
このような状況を想定すると、ftpサーバがあり、毎日頻繁にこのftpサービスのファイルをダウンロードしていますが、ほとんど数日で更新されます.私たちがファイルをダウンロードするたびに、ファイルを読み取るときにファイルをロックして、他の人がファイルを書き込むことがないことを保証します.しかし、これらのロックの行為は、99%の場合、同時にファイルに書き込む人はいません.1%の場合、同時にファイルに書き込む人もいます.これでは、私たちがロックを多くすると無駄になります.また、ロックをかけると同時に、他の人がファイルを読むだけでも、先にロックを解除するのを待つ必要があります.
この問題を解決する方法は,ファイルの読み取りに共有ロックを設定し,複数のスレッドが同時にファイルを読み取ることができ,互いにブロックされないようにすることである.さらに排他ロックを設定し、ファイルを書き込むときに排他ロックを加えると、他のスレッドが読み書きできなくなります.
Windowsは、この問題を解決するためにslimと呼ばれる共有/独占ロックを提供しています.しかし、slimはvistaとwindow server 2008でしかサポートされていません.以前のバージョンではサポートされていませんでした.そこで、wは既存のスレッド同期手段を利用して、slimという共有/独占ロックの機能をシミュレートし、コードパッケージは以下の通りである.
</pre><pre name="code" class="cpp">//      (   ,  ),                   
//   :         ,     。
//   :            ,       
//  :acquire release      ,           
//  :                ,          
#ifdef __cplusplus
extern "C" {
#endif
struct 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