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の考え方なのかしら?