2016-11-28 77 views
2

我需要在工作方法中对unique_lock :: owns_lock()进行断言,但我不'想要传递unique_lock作为参数,而是将其用作静态变量。但这意味着我不能使用unique_lock来实现其RAII行为。 有这样的代码是否公平:是std :: lock_guard <std :: unique_lock <std::mutex>>有效还是推荐?

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

这样做似乎有效。 的#include “stdafx.h中” #包括使用命名空间std 的#include 的#include 的#include ; namespace { mutex gMtx; unique_lock gLock(gMtx,defer_lock); } void foo(const string&msg) assert(gLock.owns_lock()); cout << msg << endl; } void bar() { lock_guard > lock(gLock); foo(“bar()”); } int main() { bar(); return 0; } – asterisc

+0

作为解决方法,您可以将互斥量更改为recursive_mutex,并将其锁定在'foo()'中。 –

回答

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被销毁之前未在任何地方解锁),它可能会在实践中发挥作用。

+0

标准中有一个注释说*“[注意:'unique_lock '符合'BasicLockable'的要求[...]]”*,但正如您所指出的那样,std :: unique_lock :: unlock '不符合'BasicLockable :: unlock'的要求,这有点奇怪... – Holt

+0

我把这个明显的冲突发布到了[std-discussion](https://isocpp.org/forums/iso-c-standard -discussion?place = msg%2Fstd-discussion%2F7FELSZvOX3c%2FHbsrjeSNCAAJ)邮件列表。我的感觉(在看到任何答案之前)是没问题的,因为'std :: unique_lock :: unlock()'抛出的唯一方法就是它[不拥有锁](http://eel.is /c++draft/thread.lock.unique#locking-26.1),'BasicLockable'具有调用'unlock()'[当前执行代理拥有锁]的先决条件(http://eel.is/ C++草案/ thread.req.lockable.basic#3)。 – TBBle

0

根据当前的C++ standard draft,这看起来是有效的,同样的文本适用于C++11,只有一个段落编号更改。

The thing passed as the template argument to std::lock_guard must be a BasicLockable

BasicLockable指定两件事情:

  1. lock(),它没有要求或限制超出要么获取锁抛出异常。
  2. unlock(),只能在锁定时才能调用,不能失败,并且不能抛出异常

unique_lock::lock似乎满足第一个条款,但请参阅下面的分隔线。

unique_lock::unlock满足第二条的要求,理由是其下unique_lock::unlock可能抛出的唯一情况是,如果锁定目前尚未举行,并BasicLockable要求时unlock被称为持有锁。

这与我在将此读数提交到isocpp.org std-discussion邮件列表时收到的唯一回复相匹配。


如果unique_lock已经举行,看来对于BasicLockable的要求被违反,作为当前execution agent持有锁,抛出一个异常。由于确切的措词是

如果引发异常,则不应获取当前执行代理的锁定。

人们可以说,锁不收购,因为它已经举行。

相关问题