【问题标题】:Is it possible to determine is a boost::basic_lockable_adapter is currently locked?是否可以确定 boost::basic_lockable_adapter 当前已锁定?
【发布时间】:2016-01-29 15:15:33
【问题描述】:

我们一直在项目中使用 Boost 的 basic_lockable_adapterstrict_lock 进行线程同步。我们已经确定了一种可能导致死锁的情况,并且我们希望避免这种情况。如果我们能够检测到basic_lockable_adapter 是否被锁定,我们可以断言它并在开发过程中捕获它。

这是我正在寻找的示例(此代码是可编译的,除了一个函数不存在这一事实):

#include <boost/thread/lockable_adapter.hpp>
#include <boost/thread/strict_lock.hpp>
#include <mutex>

class Controller : public boost::basic_lockable_adapter<std::recursive_mutex>
{
public:
    static Controller& instance() { static Controller instance; return instance; }
};

void check_for_lock()
{
    // is_locked() isn't real ... but I'd like that functionality somehow
    if (Controller::instance().is_locked())
        std::cout << "It's locked." << std::endl;
    else
        std::cout << "Not locked." << std::endl;
}

int main()
{
    check_for_lock();
    boost::strict_lock<Controller> lock(Controller::instance());
    check_for_lock();

    return 0;
}

是否可以实现.is_locked()的等价物?

编辑 - 澄清

我忘了提一个重点。我们使用 Boost 文档中解释的“外部锁定”范例。这样,一个绝对需要持有锁的函数只需要一个引用作为参数——因此,如果你得到这个参数,你就知道你有锁。

在我的情况下,情况正好相反。我想知道当前线程当前是否有锁,来自一个不期望strict_lock作为参数的函数,所以我可以断言或抛出。

所以:该函数知道lockable_adapter 是什么,但需要知道当前执行的线程是否有那个锁(它不关心其他线程)。

【问题讨论】:

    标签: c++ boost locking mutex


    【解决方案1】:

    严格的锁/总是/拥有锁(这就是他们严格的原因)。

    unique_lockowns_lock(): http://en.cppreference.com/w/cpp/thread/unique_lock/owns_lock。它还具有到 bool 的隐式转换,效果完全一样!

    您可以静态地确定泛型类型是否为严格锁定。在 boost 文档中有一个关于如何将其拼凑成通用锁类型的大量讨论:Allowing other strict locks

    【讨论】:

    • 我不确定这是否完全回答了问题 - 但晚餐供应:|稍后重温
    • 你说的很对,但是我忘了在我的问题中添加一个重要的细节——它现在已经更新了。我需要知道当前线程此刻是否有锁,来自一个不以strict_lock为参数的函数。
    【解决方案2】:

    我不相信使用朴素的std::recursive_mutex 你的目标是 100% 可行的。尽管您可以通过在当前线程和单独的线程上调用 try_lock() 来尝试测试锁,但分析这些结果不会给您一个明确的答案。原因之一是该标准允许try_lock() 虚假失败,即使互斥锁可用。另一个原因是递归有实现定义的限制,在此之后try_lock() 将失败。

    你能用你自己的互斥锁类型代替吗?如果是这样,那么您可以使用您自己的类来包装std::recursive_mutex,该类记录持有锁的线程。例如:

    #include <mutex>
    #include <thread>
    #include <boost/thread/lockable_adapter.hpp>
    #include <boost/thread/strict_lock.hpp>
    
    class MyMutex {
       std::recursive_mutex m_;
    
       std::mutex auxMutex_;
       std::thread::id id_;
       unsigned int count_;
    public:
       MyMutex() : count_(0) {}
    
       void lock() {
          m_.lock();
          std::lock_guard<std::mutex> lock(auxMutex_);
          if (!count_++)
             id_ = std::this_thread::get_id();
       }
    
       void unlock() {
          std::lock_guard<std::mutex> lock(auxMutex_);
          --count_;
          m_.unlock();
       }
    
       bool try_lock() {
          if (m_.try_lock()) {
             std::lock_guard<std::mutex> lock(auxMutex_);
             if (!count_++)
                id_ = std::this_thread::get_id();
             return true;
          }
          return false;
       }
    
       std::thread::id id() {
          std::lock_guard<std::mutex> lock(auxMutex_);
          return count_ ? id_ : std::thread::id();
       }
    };
    
    class Controller : public boost::basic_lockable_adapter<MyMutex>
    {
       // Allow access to protected lockable() member function.
       friend void check_for_lock();
    
    public:
        static Controller& instance() { static Controller instance; return instance; }
    };
    
    void check_for_lock()
    {
       auto& lockable = Controller::instance().lockable();
       if (lockable.id() == std::this_thread::get_id())
          std::cout << "locked in current thread" << std::endl;
       else
          std::cout << "not locked in current thread" << std::endl;
    }
    
    int main()
    {
        check_for_lock();
        boost::strict_lock<Controller> lock(Controller::instance());
        check_for_lock();
    
        return 0;
    }
    

    在包装类MyMutex 中,count_ 跟踪递归级别,id_ 记录最后一个要锁定的线程。否则,锁操作调用将被转发到实际的std::recursive_mutex

    从适配器获取对互斥锁的引用确实需要访问受保护的lockable() 成员函数。因此,我将check_for_lock() 设为好友函数,或者将其设为成员函数。它的实现变成了比较线程 id 的简单问题。

    【讨论】:

    • 我认为需要某种包装器,但我不确定它是否应该在 lockable_adapterstrict_lockmutex 周围。明天我会实施这样的事情,如果它完成了这项工作,那么赏金就是你的。 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-10
    • 1970-01-01
    • 2015-12-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多