我需要在一个工作方法中对unique_lock :: owns_lock()断言,但我不想将unique_lock作为参数传递,而是将其用作静态变量。但这意味着我不能将unique_lock用于其RAII行为。 拥有如下代码是否公平:
namespace
{
std::mutex gMtx;
std::unique_lock<std::mutex> gLock(gMtx, std::defer_lock);
}
void foo()
{
assert(gLock.owns_lock());
// ...
}
void bar()
{
std::lock_guard<std::unique_lock<std::mutex>> lock(gLock);
//...
foo();
//...
}
思想?
答案 0 :(得分:1)
标准尚不清楚这种结构的有效性。
std::lock_guard
的模板参数必须符合BasicLockable requirements,即必须包含lock()
和unlock()
函数。
std::unique_lock
具有这些功能,这意味着代码可以编译。但是,它们不能像BasicLockable那样工作。 unlock()
不应该抛出异常,但std::unique_lock::unlock()
可以抛出异常。根据这一点,使用std::lock_guard<std::unique_lock<std::mutex>>
应该是未定义的行为。
但是,正如Holt在评论中指出的那样,该标准还表示unique_lock
符合BasicLockable要求。因此不清楚行为是否已定义。如果你可以保证unlock()
没有抛出(在lock_guard
被销毁之前,互斥锁没有被解锁),它可能会在实践中发挥作用。
答案 1 :(得分:0)
根据当前的C++ standard draft,这似乎是有效的,同一文字适用于C++11,只有一个段落编号更改。
The thing passed as the template argument to std::lock_guard
must be a BasicLockable
BasicLockable
指定了两件事:
lock()
,除了获取锁定或抛出异常之外没有任何要求或限制。unlock()
只能在持有锁定时调用,不能失败,不能抛出异常。 unique_lock::lock
似乎满足第一个条款,但请参见下面的分隔线。
unique_lock::unlock
满足第二个条款的要求,因为unique_lock::unlock
可能抛出的唯一情况是当前没有锁定,BasicLockable
要求在调用unlock
时保持锁定。
这与我在isocpp.org std-discussion邮件列表中提出此阅读时收到的唯一回复相符。
如果unique_lock
已被占用,则似乎违反了BasicLockable
的要求,因为当前execution agent持有锁,和例外被扔了。由于确切的措辞是
如果抛出异常,则不应为当前执行代理获取锁定。
有人可能认为锁定并非获得,因为它已经被保留了。