Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/134.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 当被调用的方法使用调用方已经锁定的锁时,如何避免死锁?_C++_C++11_Mutex - Fatal编程技术网

C++ 当被调用的方法使用调用方已经锁定的锁时,如何避免死锁?

C++ 当被调用的方法使用调用方已经锁定的锁时,如何避免死锁?,c++,c++11,mutex,C++,C++11,Mutex,当被调用的方法使用调用方已经锁定的锁时,如何避免死锁? 我有一个名为closeUnusedConnections()的方法,它创建了一个std::unique\u锁,但它的调用者已经使用相同的std::mutex:Foo::m\u myMutex创建了一个std::unique\u锁 调用子例程之前是否必须释放锁 Obs.:我无法集成这两种方法,因为closeUnusedConnections也被独立调用 一些代码: void Foo::closeUnusedConnections() {

当被调用的方法使用调用方已经锁定的锁时,如何避免死锁?

我有一个名为closeUnusedConnections()的方法,它创建了一个
std::unique\u锁
,但它的调用者已经使用相同的
std::mutex
:Foo::m\u myMutex创建了一个
std::unique\u锁

调用子例程之前是否必须释放锁

Obs.:我无法集成这两种方法,因为closeUnusedConnections也被独立调用

一些代码:

void Foo::closeUnusedConnections()
{   
   std::unique_lock< std::mutex > lock( m_mtx );
   // do stuff
}

Foo::CommNodePtr Foo::getConnection()
{   
   std::unique_lock< std::mutex > lock( m_mtx );
   // do stuff
   if( true /*some condition*/ )
   {
      lock.unlock();     // The goal is to avoid this unlock
                         // someone could get the lock between
                         // this unlock until closeUnusedConnections's lock.
      closeUnusedConnections(); 
   }
   // etc
}
void Foo::closeUnusedConnections()
{   
std::unique_locklock(m_mtx);
//做事
}
Foo::CommNodePtr Foo::getConnection()
{   
std::unique_locklock(m_mtx);
//做事
if(true/*某些条件*/)
{
lock.unlock();//目标是避免这种解锁
//有人可能会在两人之间找到锁
//这将解锁,直到关闭未使用的连接的锁。
关闭未使用的连接();
}
//等
}

创建一个私有函数,该函数可以在不抓住锁的情况下完成工作

//call with m_mtx locked
void Foo::unlockedCloseUnusedConnections()
{     
   // do stuff
}
你的公共职能刚刚开始

 void Foo::closeUnusedConnections()
 {
     std::unique_lock< std::mutex > lock( m_mtx );
     unlockedCloseUnusedConnections();
 }
void Foo::closeUnusedConnections()
{
std::unique_locklock(m_mtx);
解除锁定CloseUnusedConnections();
}

您的
Foo::getConnection()
函数调用
unlockedCloseUnusedConnections()
,因为它已经获得了锁。

我认为在单个所有者线程之外有一个对象的访问器是非常危险的,因为该对象可以被其他线程删除、关闭。互斥锁应该在它们拥有另一个线程时防止这些事情发生

nos的解决方案在您描述的方面对您有效,但我觉得您最终会遇到其他问题,因为在调用
getConnection
后,当一个线程正在被另一个线程使用时,没有任何东西可以阻止一个线程关闭连接

我有点想知道,如果调用
getConnection
,调用可能会返回一个已关闭的连接,那么您试图实现什么

我的建议是重新考虑您的工作流程,以便在任何给定时刻只有一个线程可以访问您的端口,即使这意味着只有一个线程可以使用端口,而其他线程必须发出工作请求。

这种“我的类拥有一个互斥锁,它在所有操作上锁定它”的模式很糟糕。它不构成或缩放

使用递归互斥体可以解决一些问题,但两者都有更高的成本,并且不能解决互斥体应该非常狭窄或非常明确的更大问题

互斥是危险的。僵局难以避免。共享状态是一个雷区

一种方法是围绕类编写包装器,如下所示:

template<class T>
struct mutex_guarded {
  template<class F>
  auto operator->*( F&& f )
  -> decltype( std::forward<F>(std::declval<T&>()) )
  {
    std::unique_lock<std::mutex> l(m_mtx);
    return std::forward<F>(f)(t);
  }
  template<class F>
  auto operator->*( F&& f ) const
  -> decltype( std::forward<F>(std::declval<T const&>()) )
  {
    std::unique_lock<std::mutex> l(m_mtx);
    return std::forward<F>(f)(t);
  }
  mutex_guarded(T tin):t(std::move(tin)) {}
  T copy_out() const {
    return (*this)->*[](auto& t){ return t; };
  }
  T move_out() {
    return (*this)->*[](auto& t){ return std::move(t); };
  }
  template<class U>
  void assign(U&& u) {
    return (*this)->*[&u](auto& t) { t = std::forward<U>(u); }
  }
  mutex_guarded(T const& tin):t(tin) {}
  mutex_guarded(T && tin):t(std::move(tin)) {}
  mutex_guarded(mutex_guarded const& tin):
    mutex_guarded(tin.copy_out())
  {}
  mutex_guarded(mutex_guarded && tin):
    mutex_guarded(tin.move_out())
  {}
  mutex_guarded& operator=(T const& tin) {
    assign( tin );
    return *this;
  }
  mutex_guarded& operator=(T&& tin) {
    assign( std::move(tin) );
    return *this;
  }
  mutex_guarded& operator=(mutex_guarded const& tin) {
    return *this = tin.copy_out();
  }
  mutex_guarded& operator=(mutex_guarded&& tin) {
    return *this = tin.move_out();
  }
private:
  std::mutex m_mtx;
  T t;
};
并且锁定发生在
互斥锁中,而不是在
Foo
本身中
Foo
本身没有任何线程安全性,它自己的调用不会导致问题


这仍然是危险的。互斥体通常是危险的,控制得越不严格,它们就越危险。

您可能会使用递归互斥体。但是对你的设计考虑得更仔细一点可能是个更好的主意。为什么一个名为
getConnection
的函数会担心关闭未使用的连接呢?该函数只应返回已使用或未使用的连接。我同意杰斯珀·尤尔的观点;重新考虑一下你的设计,互斥锁问题可能就会消失。这里有很多问题。最突出的不是互斥锁,而是一个名为
getConnection()
的函数担心未使用的连接。我相信你的建议可能是一个包袱,因为它没有解决设置这两个函数需要的基本设计问题。这部分代码将需要重新设计。closeconnections方法不会关闭实际调用,而是关闭池中的其他长空闲连接。这是一个阻塞呼叫,但重新设计将进入另一个时间框。
foo->*[&](auto& foo){ foo.closeUnusedConnections(); };