【问题标题】:boost::mutex / How to test if a mutex is lockedboost::mutex / 如何测试互斥锁是否被锁定
【发布时间】:2010-12-26 15:47:50
【问题描述】:

我知道,我知道,我的邮件标题可能看起来很挑衅,因为 boost::mutex 有目的地不暴露锁/解锁(为了避免死锁)。

但是,boost 文档在这些方面非常短(至少可以这么说),所以我想问是否有人可以在以下用例中帮助我。

假设你有一个类 Foo,它有:
- 需要一些时间才能完成的析构函数
- 由不同线程调用的方法,但在销毁期间不应调用

class Foo
{
 public:

  virtual ~Foo()
  { 
    //Time consuming operations here
  }


  //Method called by a timer belonging to a distinct class 
  void OnTimer()
  {
    //Other time consuming stuff. Should not be called during destruction !
  }  


}; 

我尝试(没有成功)实现一个基于 boost::mutex 的版本

//boost::mutex implementation
class Foo
{
public:
  Foo()
  {
  }

  virtual ~Foo()
  { 
    {
      boost::mutex::scoped_lock lock(mDisposingMutex);
      //Time consuming operations here
    }
  }


  //Method called by a timer belonging to a distinct class 
  void OnTimer()
  {
    {
      //Imaginary code here: mutex::locked() method is private !!!
      if ( ! mDisposingMutex.locked()) 
        return;
    }    
    //Other time consuming stuff. Should not be called during destruction !
  }  

private:
  boost::mutex mDisposingMutex; 
}; 

我完全错了吗?谁能告诉我这应该如何使用 boost::mutex 来完成?

谢谢!

【问题讨论】:

  • 为什么你的对象被破坏了,而另一个线程仍然有指向它的指针?
  • 不直接回答问题,你能取消注册引发OnTimer()调用作为你的析构函数的第一步吗?当然,调用仍然可以“同时”异步进行,但目前尚不清楚为什么这个正在销毁的对象仍然是这些回调的目标。
  • @Anon :同意,这是代码异味。不过,我仍然对答案感兴趣。 @Seh:您的评论基于相同的代码气味。但是,我不能在不破坏封装的情况下直接取消它。
  • 要考虑的另一种替代方法:忘记互斥锁并定义一个状态模型,您可以在其中移动原子转换,例如 Java 库的 FutureTask 类。定义一个枚举状态模型,包括ALIVEDESTRUCTINGDESTRUCTED(可能)。进入析构函数后,以原子方式将状态更改为 DESTRUCTING(如果您偏执,则通过 CAS),并(可能)在退出析构函数时将其更改为 DESTRUCTED。在OnTimer() 中,仅当状态为 ALIVE 时才执行工作。如果你需要阻止析构函数在OnTimer() 运行时启动,你需要一个锁。

标签: boost mutex


【解决方案1】:

互斥锁::try_lock()

【讨论】:

  • 如果您是锁定互斥锁的人,则返回 false。
【解决方案2】:

如果您确实承诺在析构函数体中使用Lockable::lock(),您可以让您的OnTimer() 函数使用Lockable::try_lock(),并且仅在该函数返回true 时继续。如果OnTimer() 首先启动,那将让OnTimer() 暂停析构函数,但它仍然不能解决析构函数运行、完成和释放互斥锁,然后是OnTimer() 的问题启动并成功获取互斥锁。

这样的序列很可能在未定义行为的范围内,但该诅咒不会阻止它的发生。除了互斥体之外,使用状态标志 - 类似于我在上面的评论中描述的 - 可以让您检测到后一种情况并阻止OnTimer() 除了读取标志之外做任何事情。但是,在某些时候,这只是将创可贴放在创可贴之上。

【讨论】:

    【解决方案3】:

    @Seh :我完全同意这是代码异味,我应该(并且将)纠正根本原因。

    但是,为了帮助遇到与我相同问题的任何人(即与 boost doc 斗争),我尝试实施您的建议。 下面的代码现在可以正确编译(尽管现在代码味道很重)

    #include <boost/thread/mutex.hpp>
    
    //boost::mutex implementation
    class Foo
    {
    public:
      Foo() :
        mIsDisposing(false)
      {
      }
    
      virtual ~Foo()
      { 
        {
          boost::try_mutex::scoped_try_lock lock(mDisposingMutex);
          if ( ! lock.locked())
          {
            //Die by horrible death, or wait before trying again...
          }
          else
          {
            mIsDisposing = true;
          }
          //Time consuming operations here
        }
    
      }
    
    
      //Method called by a timer belonging to a distinct class 
      void OnTimer()
      {
        {
          boost::try_mutex::scoped_try_lock lock(mDisposingMutex);
          if ( ! lock.locked() || mIsDisposing )
          {
            return;      
          }
        }    
        //Other time consuming stuff. Should not be called during destruction !
      }  
    
    private:
      boost::try_mutex mDisposingMutex; 
      bool mIsDisposing;
    };
    

    【讨论】:

      猜你喜欢
      • 2013-02-02
      • 1970-01-01
      • 2013-01-15
      • 1970-01-01
      • 2022-06-13
      • 2021-06-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多