是否可以确定 boost::basic_lockable_adapter 当前是否被锁定?

Is it possible to determine is a boost::basic_lockable_adapter is currently locked?

我们一直在项目中使用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() 的等价物?

编辑 - 澄清

我忘了提一个重点。我们使用 "external locking" 范例,如 Boost 文档中所述。这样,一个绝对需要持有锁的函数只需要一个引用作为参数——因此,如果你得到这个参数,你就知道你有锁。

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

因此:该函数知道 lockable_adapter 是什么,但需要知道当前正在执行的线程是否具有该锁(它不关心其他线程)。

严格锁/始终/拥有锁(这就是它们 严格 的原因)。

unique_lockowns_lock()http://en.cppreference.com/w/cpp/thread/unique_lock/owns_lock。它还具有到 bool 的隐式转换,其作用完全相同!

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

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

你能替换成你自己的互斥锁类型吗?如果是这样,那么你可以用你自己的 class 包装 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;
}

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

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