C++のマルチスレッド:MutexとCritical Sectionの利用
C++では、ミューテックスやクリティカルセクションを利用してマルチスレッドでの同期待ちを実現できます。
ミューテックス
排他制御は、共有リソースに単一のスレッドのみがアクセスできるようにする同期メカニズムです。 1つのスレッドが排他制御を獲得すると、ほかのスレッドは共有リソースにアクセスしてロックを解除するまで待機する必要があります。
ミューテックスを使用する基本ステップは次のとおりです。
保護対象のコード片の手前にミューテックスオブジェクトを作成する。
スレッドが共有リソースを使用する前に、Mutexのlock()メソッドを呼び出します。
共有リソースに対するコードを実行する。
スレッドが共有リソースの操作を完了すると、同期オブジェクトの unlock() メソッドを呼び出してロックを解放します。
ミューテックスを使ったサンプルコードを以下に示します。
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx;
void PrintMessage(const std::string& message)
{
mtx.lock();
std::cout << message << std::endl;
mtx.unlock();
}
int main()
{
std::thread t1(PrintMessage, “Hello”);
std::thread t2(PrintMessage, “World”);
t1.join();
t2.join();
return 0;
}
上記の例では、PrintMessage()関数が 2 つのスレッドから同時に呼び出されていますが、ミューテックスを使用しているため、1度に1つのスレッドしかstd::cout出力ストリームにアクセスできません。
クリティカルセクション:
クリティカルセクションとは同時に複数のスレッドが共有リソースにアクセスしないように、相互排他的に実行される必要があるコード領域。Windowsではクリティカルセクションオブジェクトを使ってクリティカルセクションの同期を実現する。
クリティカルセクションを使用するための基本的な手順は次のとおりです:
保護が必要なコードセクションの前でクリティカルセクションオブジェクトを作成します。
スレッドは、共有リソースに入る前に、クリティカルセクションのEnterCriticalSection()関数を呼び出します。
共有リソースを実行するコード
4. スレッドが共有リソースに対する処理を終えた場合は、クリティカルセクションのLeaveCriticalSection()関数を呼び出してクリティカルセクションを解除します。
以下にクリティカルセクションを使用するサンプルコードを示します。
#include <iostream>
#include <thread>
#include <Windows.h>
CRITICAL_SECTION cs;
void PrintMessage(const std::string& message)
{
EnterCriticalSection(&cs);
std::cout << message << std::endl;
LeaveCriticalSection(&cs);
}
int main()
{
InitializeCriticalSection(&cs);
std::thread t1(PrintMessage, “Hello”);
std::thread t2(PrintMessage, “World”);
t1.join();
t2.join();
DeleteCriticalSection(&cs);
return 0;
}
先の例では、PrintMessage()関数は二つのスレッドから同時に呼び出されましたが、クリティカルセクションが用いられたため、std::cout出力ストリームにアクセスできるのは、各瞬間で1スレッドのみです。
ミューテックスとクリティカルセクションのいずれを使用しても、マルチスレッド環境下で共有リソースへの安全なアクセスを確保できます。どの同期メカニズムを使用するかは、具体的なニーズとプラットフォームによって異なります。