注意:这个问题涉及C++ 11.C++ 17(或更高版本)中相同问题的答案可能已经改变.详情如下:
当我们想要锁定多个时std::mutex
,我们使用std::lock()
.但std::lock()
不提供RAII功能.
当我们想以std::mutex
RAII方式锁定时,我们使用std::lock_guard
.但std::lock_guard
不能std::mutex
安全地锁定多个's.
有没有办法利用这两种方法的优势,以std::mutex
RAII的方式锁定多个?
(注意:使用std :: lock(c ++ 11)对大量CPU负载进行评论时,大部分内容都是多余的,但我认为这个主题应该得到自己的问题和答案.)
我最近遇到了一些示例C++ 11代码:
std::unique_lock<std::mutex> lock1(from_acct.mutex, std::defer_lock);
std::unique_lock<std::mutex> lock2(to_acct.mutex, std::defer_lock);
std::lock(lock1, lock2); // avoid deadlock
transfer_money(from_acct, to_acct, amount);
Run Code Online (Sandbox Code Playgroud)
哇,我想,std::lock
听起来很有趣.我想知道它的标准是什么意思?
C++ 11第30.4.3节[thread.lock.algorithm],第(4)和(5)段:
模板空锁(L1&,L2&,L3&...);
4 要求:每个模板参数类型应满足可锁定要求,[注意:
unique_lock
类模板在适当实例化时满足这些要求. - 结束说明]5种效果:所有参数通过调用的顺序被锁定
lock()
,try_lock()
或unlock()
在每个参数.调用序列不应导致死锁,否则不会被指定.[注意:必须使用诸如try-and-back-off之类的死锁避免算法,但未指定特定算法以避免过度约束实现.- 结束注释]如果调用lock()
或try_lock()
抛出异常,unlock()
则应调用已被lock()
或调用锁定的任何参数try_lock()
.
请考虑以下示例.称之为"示例1":
Thread 1 Thread 2
std::lock(lock1, lock2); std::lock(lock2, lock1);
Run Code Online (Sandbox Code Playgroud)
这可能是僵局吗?
对标准的简单解读说"不".大!也许编译器可以为我订购我的锁,这将是一种整洁.
现在尝试例2:
Thread 1 Thread 2
std::lock(lock1, lock2, lock3, lock4); std::lock(lock3, lock4); …
Run Code Online (Sandbox Code Playgroud) 我试图熟悉c ++ 11的新内存排序概念,并相信我对它们有很好的把握,直到我偶然发现了自旋锁的这种实现:
#include <atomic>
namespace JayZ
{
namespace Tools
{
class SpinLock
{
private:
std::atomic_flag spin_lock;
public:
inline SpinLock( void ) : atomic_flag( ATOMIC_FLAG_INIT ) {}
inline void lock( void )
{
while( spin_lock.test_and_set( std::memory_order_acquire ) )
;
}
inline void unlock( void )
{
lock.clear( std::memory_order_release );
}
};
}
}
Run Code Online (Sandbox Code Playgroud)
例如,在http://en.cppreference.com/w/cpp/atomic/atomic_flag
和"并行行动"一书中提到了相同的内容.我也在SO的某处找到了它.
但我只是不明白它为什么会起作用!
想象一下,线程1调用lock(),test_and_set()返回0作为旧值 - >线程1获得锁定.
但随后线程2出现并尝试相同.现在因为没有发生"存储同步"(release,seq_cst_acq_rel),所以线程1的spin_lock存储应该是轻松的类型.
但是由此得出它不能与线程2的spin_lock读取同步.这应该使线程2能够从spin_lock读取值0,从而获得锁定.
我的错误在哪里?
在什么情况下会使用这种release
方法std::unique_lock
?我犯了使用release
方法而不是方法的错误,unlock
并花了一些时间来理解为什么以下代码不起作用.
#include <mutex>
#include <iostream>
#include <vector>
#include <thread>
#include <chrono>
std::mutex mtx;
void foo()
{
std::unique_lock<std::mutex> lock(mtx);
std::cout << "in critical section\n";
std::this_thread::sleep_for(std::chrono::seconds(1));
lock.release();
}
int main()
{
std::vector<std::thread> threads;
for (int i = 0; i < 5; ++i)
threads.push_back(std::thread(foo));
for (std::thread& t : threads)
t.join();
}
Run Code Online (Sandbox Code Playgroud)