これは、Boost ヘッダーに基づいた簡単な回答です (Boost を承認済みの方法と呼びます)。条件変数とミューテックスのみが必要です。Windows プリミティブは説明的で非常に単純だと思うので、Windows プリミティブを使用して書き直しましたが、これは疑似コードと見なします。
これは非常に単純な解決策であり、mutex のアップグレードや try_lock() 操作などをサポートしていません。必要に応じて追加できます。また、厳密には必要ではない割り込みを無効にするなど、いくつかのフリルを取り除きました。
また、チェックアウトする価値がありますboost\thread\pthread\shared_mutex.hpp
(これはそれに基づいています)。人間が読める形式です。
class SharedMutex {
CRITICAL_SECTION m_state_mutex;
CONDITION_VARIABLE m_shared_cond;
CONDITION_VARIABLE m_exclusive_cond;
size_t shared_count;
bool exclusive;
// This causes write blocks to prevent further read blocks
bool exclusive_wait_blocked;
SharedMutex() : shared_count(0), exclusive(false)
{
InitializeConditionVariable (m_shared_cond);
InitializeConditionVariable (m_exclusive_cond);
InitializeCriticalSection (m_state_mutex);
}
~SharedMutex()
{
DeleteCriticalSection (&m_state_mutex);
DeleteConditionVariable (&m_exclusive_cond);
DeleteConditionVariable (&m_shared_cond);
}
// Write lock
void lock(void)
{
EnterCriticalSection (&m_state_mutex);
while (shared_count > 0 || exclusive)
{
exclusive_waiting_blocked = true;
SleepConditionVariableCS (&m_exclusive_cond, &m_state_mutex, INFINITE)
}
// This thread now 'owns' the mutex
exclusive = true;
LeaveCriticalSection (&m_state_mutex);
}
void unlock(void)
{
EnterCriticalSection (&m_state_mutex);
exclusive = false;
exclusive_waiting_blocked = false;
LeaveCriticalSection (&m_state_mutex);
WakeConditionVariable (&m_exclusive_cond);
WakeAllConditionVariable (&m_shared_cond);
}
// Read lock
void lock_shared(void)
{
EnterCriticalSection (&m_state_mutex);
while (exclusive || exclusive_waiting_blocked)
{
SleepConditionVariableCS (&m_shared_cond, m_state_mutex, INFINITE);
}
++shared_count;
LeaveCriticalSection (&m_state_mutex);
}
void unlock_shared(void)
{
EnterCriticalSection (&m_state_mutex);
--shared_count;
if (shared_count == 0)
{
exclusive_waiting_blocked = false;
LeaveCriticalSection (&m_state_mutex);
WakeConditionVariable (&m_exclusive_cond);
WakeAllConditionVariable (&m_shared_cond);
}
else
{
LeaveCriticalSection (&m_state_mutex);
}
}
};
行動
さて、このアルゴリズムの動作には混乱があるので、その仕組みを次に示します。
書き込みロック中- リーダーとライターの両方がブロックされます。
書き込みロックの終了時- リーダー スレッドと 1 つのライター スレッドが競合して、どちらが開始するかを確認します。
読み取りロック中- ライターはブロックされます。ライターがブロックされている場合にのみ、リーダーもブロックされます。
最後の読み取りロックの解放時に、リーダー スレッドと 1 つのライター スレッドが競合して、どちらが開始するかを確認します。
これにより、プロセッサーが during 通知の前に頻繁にコンテキストをスレッドに切り替えると、リーダーがライターを飢えさせる可能性がありますが、Boost のアルゴリズムであるため、この問題は理論的なものであり、実用的ではないと思います。m_shared_cond
m_exclusive_cond