multiprocess in C++ with Windows
ついでにプロセス関係も、ってことでmutexとsemaphore。
#include <windows.h> #include <string> namespace multiprocess { // mutex ----------------------------------------------------------------- class mutex { HANDLE m_handle; std::string m_name; public: // 生成・消滅 mutex(const std::string & name = "") : m_handle(NULL), m_name(name) { m_handle = CreateMutex(NULL, FALSE, m_name.empty() ? NULL : m_name.c_str()); } ~mutex() { if(m_handle) CloseHandle(m_handle); } // 情報取得 const std::string & name() const { return m_name; } // lock/unlock void lock() const { WaitForSingleObject(m_handle, INFINITE); } void unlock() const { ReleaseMutex(m_handle); } // lockできるかどうか試みる // 成功したらtrue bool try_lock() { return (WaitForSingleObject(m_handle, 0) == WAIT_OBJECT_0); } private: mutex(const mutex &); const mutex operator=(const mutex &); }; // semaphore ------------------------------------------------------------- class semaphore { HANDLE m_handle; std::string m_name; long m_max; public: // 生成・消滅 // デフォルトコンストラクタを使うならmaterializeを明示的に呼び出すこと semaphore(const std::string & name = "") : m_handle(NULL), m_name(name), m_max() {} semaphore(const long start, const long max, const std::string & name = "") : m_handle(NULL), m_name(name), m_max(max) { materialize(start); } semaphore(const long max, const std::string & name = "") : m_handle(NULL), m_name(name), m_max(max) { materialize(max); } void materialize(const long start) { if(!m_handle) m_handle = CreateSemaphore(NULL, start, m_max, m_name.empty() ? NULL : m_name.c_str()); } ~semaphore() { if(m_handle) CloseHandle(m_handle); } // 情報取得 const std::string & name() const { return m_name; } void max_count (const long new_max) { m_max = new_max; } const long max_count() const { return m_max; } // get/release void get() const { WaitForSingleObject(m_handle, INFINITE); } bool release(const long step = 1) const { return !!ReleaseSemaphore(m_handle, step, NULL); } // semaphoreの現在カウントを取得できるrelease bool release(long * current, const long step = 1) const { if(ReleaseSemaphore(m_handle, step, current) != FALSE) { current += step; return true; } return false; } // semaphoreオブジェクトにお伺いをたてる bool try_get() const { return (WaitForSingleObject(m_handle, 0) == WAIT_OBJECT_0); } private: semaphore(const semaphore &); const semaphore operator=(const semaphore &); }; }
WaitForeSingleObject大活躍。こんなに重要な関数だとは思わなかったぜ…。
一応普通に使う分にはこれで問題ないと思うんだけど、セキュリティ記述子とかわかってないしわかる気がないので、損をしてるのかしてないのか、そんな感じ。あとsemaphoreは現在のカウントがReleaseSemaphore時にしかわからないのが…。任意のタイミングでsemaphoreカウントの残りがわかればタスク量のコントロールとか容易にできると思うんだけど…、とりあえず全力でぶん回すのがsemaphoreの考え方なのかしら?