mutexの基本:排他制御の仕組みとプログラムでの使い方
1. はじめに
マルチスレッドプログラミングにおいて、複数のスレッドが同時に共有リソースにアクセスすると、データの整合性が損なわれる可能性があります。これを防ぐために使用されるのがmutex(ミューテックス)です。
本記事では、mutexの基本概念から、各プログラミング言語における実装例、注意点までを解説します。
2. mutexとは何か?
mutexは「mutual exclusion(相互排他)」の略で、同時に複数のスレッドが特定のコードやデータにアクセスすることを防ぐための仕組みです。
2.1 クリティカルセクション
クリティカルセクションとは、同時に複数のスレッドが実行してはならないコードの部分を指します。mutexを使用することで、このセクションへの同時アクセスを防ぎます。
2.2 mutexの基本操作
- ロック(lock):mutexを取得し、他のスレッドのアクセスをブロックします。
- アンロック(unlock):mutexを解放し、他のスレッドがアクセスできるようにします。
3. 各言語におけるmutexの実装例
3.1 C言語(POSIX Threads)
#include <pthread.h> pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; int shared_data = 0; void* thread_func(void* arg) { pthread_mutex_lock(&mutex); // クリティカルセクション shared_data++; pthread_mutex_unlock(&mutex); return NULL; }
3.2 C++11以降
#include <mutex> std::mutex mtx; int shared_data = 0; void thread_func() { std::lock_guard<std::mutex> lock(mtx); // クリティカルセクション shared_data++; }
std::lock_guard
は、スコープを抜けると自動的にmutexを解放します。
3.3 Java
public class SharedResource { private final Object lock = new Object(); private int sharedData = 0; public void increment() { synchronized (lock) { // クリティカルセクション sharedData++; } } }
Javaでは、synchronized
キーワードを使用してmutexの機能を実現します。
3.4 Python
import threading lock = threading.Lock() shared_data = 0 def thread_func(): global shared_data with lock: # クリティカルセクション shared_data += 1
Pythonのwith
文を使用することで、mutexの取得と解放を自動的に行います。
3.5 Go
import ( "sync" ) var ( mu sync.Mutex sharedData int ) func increment() { mu.Lock() // クリティカルセクション sharedData++ mu.Unlock() }
Goでは、sync.Mutex
を使用してmutexを実現します。
4. mutex使用時の注意点
4.1 デッドロック
複数のmutexを使用する際、取得する順序が異なると、スレッドが互いに待ち続けるデッドロックが発生する可能性があります。これを防ぐためには、mutexの取得順序を統一するなどの対策が必要です。
4.2 パフォーマンスへの影響
mutexの過度な使用は、スレッドの待機時間を増加させ、パフォーマンスの低下を招く可能性があります。必要最小限の範囲でmutexを使用することが重要です。
5. まとめ
mutexは、マルチスレッドプログラミングにおいて、共有リソースへの同時アクセスを制御するための基本的なツールです。各プログラミング言語での実装方法を理解し、適切に使用することで、安全で効率的な並行処理を実現できます。