在运行时选择互斥锁或虚拟互斥锁

Tim*_*ter 3 c++ multithreading mutex boost-thread

我有一个在几个项目之间共享的类,它的一些用途是单线程的,有些是多线程的。单线程用户不想要互斥锁的开销,多线程用户不想自己做锁,希望能够有选择地运行在“单线程模式”。所以我希望能够在运行时在真实和“虚拟”互斥体之间进行选择。

理想情况下,我会shared_ptr<something>分配一个真实或虚假的互斥对象。然后我会“锁定”它而不考虑其中的内容。

unique_lock<something> guard(*mutex);
... critical section ...
Run Code Online (Sandbox Code Playgroud)

现在有一个signals2::dummy_mutex但它不与boost::mutex.

那么,在不使锁定/保护代码比上面的示例更复杂的情况下,在真实互斥锁和虚拟互斥锁(signals2 中的互斥锁或其他)之间进行选择的优雅方法是什么?

而且,在您指出替代方案之前:

  • 我可以在编译时选择一个实现,但预处理器宏很难看,而且维护项目配置对我们来说很痛苦。
  • 多线程环境中类的用户不想承担锁定类使用的责任,而不是让类在内部进行自己的锁定。
  • “线程安全包装器”涉及的 API 和现有用法太多,无法成为实用的解决方案。

Mic*_*son 5

这样的事情怎么样?它未经测试,但应该接近确定。如果您的互斥体支持正确类型的构造,您可能会考虑让模板类保存一个值而不是一个指针。否则,您可以专门使用 MyMutex 类来获取值行为。

此外,复制或销毁也不小心..我将其作为练习留给读者;)( shared_ptr 或存储值而不是指针应该解决这个问题)

哦,使用 RAII 而不是显式锁定/解锁的代码会更好......但这是一个不同的问题。我假设这就是您代码中的 unique_lock 的作用?

struct IMutex
{
  virtual ~IMutex(){}
  virtual void lock()=0;
  virtual bool try_lock()=0;
  virtual void unlock()=0;
};

template<typename T>
class MyMutex : public IMutex
{
  public:
    MyMutex(T t) : t_(t) {}
    void lock() { t_->lock(); }
    bool try_lock() { return t_->try_lock(); }
    void unlock() { t_->unlock(); }
  protected:
    T* t_;
};

IMutex * createMutex()
{
  if( isMultithreaded() )
  {
     return new MyMutex<boost::mutex>( new boost::mutex );
  }
  else
  {
     return new MyMutex<signal2::dummy_mutex>( new signal2::dummy_mutex );
  }
}


int main()
{
   IMutex * mutex = createMutex();
   ...
   {
     unique_lock<IMutex> guard( *mutex );
     ...
   }

}
Run Code Online (Sandbox Code Playgroud)