如何在调用其他使用unique_lock的函数的类中使用unique_lock?

Jas*_*son -1 c++ mutex locking c++11

我有一个类,我需要使线程安全.我试图通过在类中的每个函数的顶部放置一个独特的锁来做到这一点.问题是,只要一个函数调用另一个函数(在此类中),互斥锁似乎相互锁定,尽管它们处于不同的函数中.我怎么能阻止这种情况发生?

一个例子是一个带有get()和set()函数的类,它们在每个函数的开头都使用unique_lock.但是在set()中你想在某个时候调用get(),但是没有set()的互斥锁定get()的互斥锁.但是,如果直接调用,get()中的互斥锁仍然可以工作.

Yak*_*ont 5

通过向所有操作添加互斥锁使类"thead safe"是代码味道.使用递归互斥体这样做更糟糕,因为它意味着缺乏对锁定内容和操作锁定的控制和理解.

虽然它通常允许一些有限的多线程访问,但经常导致死锁,争用和性能下行.

除了有限的情况外,基于锁的并发不能安全地组合.您可以采用两个正确的基于锁的数据结构/算法,连接它们,最后得到错误/不安全的代码.

考虑将您的类型保留为单线程,实现const可以在不同步的情况下相互调用的方法,然后使用不可变实例和外部同步实例的混合.

template<class T>
struct mutex_guarded {
  template<class F>
  auto read( F&& f ) const {
    return access( std::forward<F>(f), *this );
  }
  template<class F>
  auto write( F&& f ) {
    return access( std::forward<F>(f), *this );
  }
  mutex_guarded()=default;
  template<class T0, class...Ts,
    std::enable_if_t<!std::is_same<mutex_guarded, std::decay_t<T0>>, bool> =true
  >
  mutex_guarded(T0&&t0, Ts&&ts):
    t(std::forward<T0>(t0),std::forward<Ts>(ts)...)
  {}
private:
  template<class F, class Self>
  friend auto access(F&& f, Self& self ){
    auto l = self.lock();
    return std::forward<F>(f)( self.t );
  }
  mutable std::mutex m;
  T t;
  auto lock() const { return std::unique_lock<std::mutex>(m); }
};
Run Code Online (Sandbox Code Playgroud)

和类似的共享互斥(它有两个lock重载). access可以公开和vararg做一些工作(处理分配工作).

现在调用自己的方法没问题.外部使用看起来像:

std::mutex_guarded<std::ostream&> safe_cout(std::cout);
safe_cout.write([&](auto& cout){ cout<<"hello "<<"world\n"; });
Run Code Online (Sandbox Code Playgroud)

你也可以编写异步包装器(在线程池中执行任务并返回期货)等.

  • 在使用递归互斥体可以解决所有锁定问题的代码库之后,我会赞同这一点 - 您可能正在用一组问题交换另一组问题。可能发生的死锁确实很难调试。您应该仔细考虑是否要封装锁定(内部锁定)或外部锁定。递归 mutices 本身几乎每次都是一种代码味道。 (2认同)