std::lock_guard的有条件使用
Conditional use of std::lock_guard
我有一个函数,其中语句foo
应该在lock_guard
下执行,但只有当指向mutex
对象的指针作为参数提供给该函数时。否则,foo
不必受到lock_guard
的保护。
我不能在if
中使用lock_guard
,因为当if
块结束时,锁将立即释放。
所以,这个代码是无稽之谈:
bar( std::mutex * optionalMutex = nullptr )
{
...
if ( nullptr != optionalMutex ) {
std::lock_guard<std::mutex> lockScope( *optionalMutex );
} <- Here the lock ends
foo... <- foo is not protected when optionalMutex was provided
}
我试过这样的东西:
bar( std::mutex * optionalMutex = nullptr )
{
...
nullptr == optionalMutex ? 0 : std::lock_guard<std::mutex> lockScope( *optionalMutex );
// this scope should be protected by lock_guard when optionalMutex was provided
foo...
}
或多或少,对我来说,唯一可能的解决方案是重复foo
:
bar( std::mutex * optionalMutex = nullptr )
{
...
if ( nullptr != optionalMutex ) {
std::lock_guard<std::mutex> lockScope( *optionalMutex );
foo...
} else {
foo...
}
}
编译器gcc 4.9.3
不编译第二个示例,并抱怨:error: expected primary-expression before 'lockScope'
更新:Superlokkus在回答中解释了原因。
但我确实想避免任何代码重复,因此也要避免重复的foo
。
我的问题:
是否有一种优雅的方法来实现这个问题,以及而不是使用重复的foo
。我知道,我可以使用lambda函数来组foo
,但我很好奇是否有其他解决方案。
这个怎么样?
void bar(std::mutex * optionalMutex = nullptr)
{
auto lockScope = (optionalMutex == nullptr) ?
std::unique_lock<std::mutex>()
: std::unique_lock<std::mutex>(*optionalMutex);
}
说明:您的编译器在之前的语句中遇到了问题,因为您不能突然更改三元?
表达式的类型;即文字CCD_ 16不是CCD_。所以我把这两个分支改为相同的类型,这里是std::unique_lock<std::mutex>
,因为lock_guard
不是在没有有效互斥的情况下使用的。但在更简单的情况下,仍然更喜欢std::lock_guard
而不是std::unique_lock
,因为它会使代码更可读。
此外,您的语句对编译器来说是不可行的,即语法正确,因为变量lockScope只存在于一个分支中。
您真正拥有的是两个函数,一个锁定,另一个不锁定。第一个可以调用第二个:
void bar() {
// whatever
}
void bar(std::mutex* mtx) {
std::lock_guard<std::mutex> lockScope(*mtx);
bar();
}
我只有这个解决方案。使用伪mutex
对象:
代码为:
bar( std::mutex * optionalMutex = nullptr )
{
...
std::mutex dummyMutex;
std::lock_guard<std::mutex> lockScope( optionalMutex ? *optionalMutex, dummyMutex );
foo... <- NOW foo is protected when optionalMutex was provided
}
这是一个小问题,但您可以通过让调用者传递std::unique_lock来避免传递原始指针:
bar( std::unique_lock<std::mutex> lockScope )
{
if(lockScope.mutex())
{
lockScope.lock();
//do things
}
}
这似乎是界面的一个更清晰的表达,并减少了滥用的可能性。
实现自己版本的lock_guard相当简单,它使用指向互斥体的指针而不是引用。
template <typename MutexT>
class conditional_lock_guard
{
private:
MutexT* const m_mtx;
public:
explicit conditional_lock_guard(MutexT* mtx) :
m_mtx{ mtx }
{
if (m_mtx != nullptr)
{
m_mtx->lock();
}
}
~conditional_lock_guard() noexcept
{
if (m_mtx != nullptr)
{
m_mtx->unlock();
}
}
conditional_lock_guard(const conditional_lock_guard&) = delete;
conditional_lock_guard& operator=(const conditional_lock_guard&) = delete;
bool owns_lock() const noexcept
{
return m_mtx != nullptr;
}
explicit operator bool() const noexcept
{
return owns_lock();
}
MutexT* mutex() const noexcept
{
return m_mtx;
}
};
Superlockus的答案已经足够好了,但我想知道你为什么不简单地这样写:
bar( std::mutex * optionalMutex = nullptr )
{
if (optionalMutex)
optionalMutex->lock():
foo...
if (optionalMutex)
optionalMutex->unlock():
}
CCD_ 23和CCD_。
- 如何使用 soong 命名空间来有条件地编译模块
- 有条件地将默认参数传递给函数(使用"?"运算符)
- 根据模板类型有条件地删除变量
- 有条件地选择带有 decltype() 和三元运算符的类型
- 如何使用 SFINAE 在方法调用中有条件地定义变量?
- 有条件的打印和计数在 std::map 上有限制
- 如何在 c++ 中有条件地包含标头?
- 如何仅在Qt是用ltcg构建时才有条件地启用ltcg?
- 如何在Visual Studio 2019中有条件地编译c++源文件
- C++可以有条件地向下转换类指针吗
- 使用 SFINAE 有条件地解析分配器成员
- 有条件地删除宏
- 有条件地包含C++标准库
- 如何有条件地将元素添加到 std::array - C++11
- 是否根据编译器版本有条件地包含源文件
- 有条件地启用类C++构造函数
- 我可以有条件地使用多个参数吗?
- 有条件地使用 Boost Python 添加模块
- 有什么东西阻止std::optional::value_or()有条件地不例外吗?
- 无法使用三元运算符有条件地分配"istream &"?