複数プロセスで共有しているmutexのロック中にSIGKILLを投げたらどうなるか
結論: デッドロックになってしまう
自動的にロックを解放してくれたりはしないみたい。
以下、試した内容のメモ書き。
環境
$ cat /proc/version Linux version 3.0.0-23-generic (buildd@komainu) (gcc version 4.6.1 (Ubuntu/Linaro 4.6.1-9ubuntu3) ) #38-Ubuntu SMP Fri Jul 6 14:43:30 UTC 2012
テスト用ソースコード
共有mutexに対して、ロック => スリープ(10秒) => アンロック、を行う子プロセスを四個作成するプログラム。
かなりテキトウ。
/** * フィル名: mutex-text.cc * コンパイル: g++ -o mutex-test mutex-test.cc */ #include <pthread.h> #include <iostream> #include <sys/types.h> #include <sys/wait.h> #include <sys/shm.h> #include <assert.h> // 共有メモリの管理クラス class mem { public: mem(int size) : ptr_(NULL) { int shmid = shmget(IPC_PRIVATE, sizeof(pthread_mutex_t), 0600); if(shmid == -1) { return; } ptr_ = shmat(shmid, NULL, 0); if(ptr_ == reinterpret_cast<void*>(-1)) { ptr_ = NULL; } } ~mem() { if(ptr_ != NULL) { shmdt(ptr_); } } operator bool() const { return ptr_ != NULL; } template <typename T> T* ptr() { return reinterpret_cast<T*>(ptr_); } private: void* ptr_; }; // 複数プロセスで共有可能なミューテックスクラス class mutex_lock { public: mutex_lock() : m_(sizeof(pthread_mutex_t)), valid_(false) { if(! m_) { return; } // プロセス間で共有可能にするためにPTHREAD_PROCESS_SHAREDを付与する pthread_mutexattr_t mattr; if(pthread_mutexattr_init(&mattr) != 0) { return; } if(pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED) != 0) { return; } // 共有領域のmutexオブジェクトを初期化 if(pthread_mutex_init(m_.ptr<pthread_mutex_t>(), &mattr) != 0) { return; } pthread_mutexattr_destroy(&mattr); valid_ = true; } ~mutex_lock() { if(valid_) { pthread_mutex_destroy(m_.ptr<pthread_mutex_t>()); } } operator bool () const { return valid_; } // ロック void lock() { assert(pthread_mutex_lock(m_.ptr<pthread_mutex_t>()) == 0); } // アンロック void unlock() { assert(pthread_mutex_unlock(m_.ptr<pthread_mutex_t>()) == 0); } private: mem m_; bool valid_; }; // main関数 int main(int argc, char** argv) { mutex_lock mutex; if(! mutex) { return 1; } pid_t parent = getpid(); for(int i=0; i < 4; i++) { // 子プロセスのforkと lock => sleep => unlock 処理 // 子プロセスは四個作成 if(fork() == 0) { std::cout << "[" << getpid() << "] before lock" << std::endl; mutex.lock(); std::cout << "[" << getpid() << "] in lock" << std::endl; sleep(10); // 適当な時間sleep mutex.unlock(); std::cout << "[" << getpid() << "] after lock" << std::endl; break; } } if(parent == getpid()) { for(int i=0; i < 4; i++) { waitid(P_ALL, 0, NULL, WEXITED); } } return 0; }
実行結果
普通に実行した場合:
$ ./mutex-test [31413] before lock [31412] before lock [31412] in lock [31415] before lock [31414] before lock [31412] after lock [31413] in lock [31413] after lock [31415] in lock [31415] after lock [31414] in lock [31414] after lock
途中で子プロセスにSIGKILLを投げた場合:
$ ./mutex-test [31443] before lock [31443] in lock # <- このプロセスにSIGKILLを投げる (kill -9 31443) [31444] before lock [31445] before lock [31446] before lock # 以後 31443 が獲得したロックが解放されることなく、デッドロックに陥る
とりあえず手元の環境では、このような挙動となった。