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