是否可以确定 boost::basic_lockable_adapter 当前是否被锁定?
Is it possible to determine is a boost::basic_lockable_adapter is currently locked?
我们一直在项目中使用Boost的basic_lockable_adapter
和strict_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_lock
有 owns_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 的简单问题。
我们一直在项目中使用Boost的basic_lockable_adapter
和strict_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_lock
有 owns_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 的简单问题。