说,我有两个线程A
和B
分别写入全局布尔变量fA
和fB
,它们最初设置为false
并且是受std::mutex
对象mA
和mB
分别保护:
// Thread A
mA.lock();
assert( fA == false );
fA = true;
mA.unlock();
// Thread B
mB.lock()
assert( fB == false );
fB = true;
mB.unlock()
是否可以在不同的帖子fA
和fB
中以不同的顺序观察C
和D
的修改?换句话说,可以使用以下程序
#include <atomic>
#include <cassert>
#include <iostream>
#include <mutex>
#include <thread>
using namespace std;
mutex mA, mB, coutMutex;
bool fA = false, fB = false;
int main()
{
thread A{ []{
lock_guard<mutex> lock{mA};
fA = true;
} };
thread B{ [] {
lock_guard<mutex> lock{mB};
fB = true;
} };
thread C{ [] { // reads fA, then fB
mA.lock();
const auto _1 = fA;
mA.unlock();
mB.lock();
const auto _2 = fB;
mB.unlock();
lock_guard<mutex> lock{coutMutex};
cout << "Thread C: fA = " << _1 << ", fB = " << _2 << endl;
} };
thread D{ [] { // reads fB, then fA (i. e. vice versa)
mB.lock();
const auto _3 = fB;
mB.unlock();
mA.lock();
const auto _4 = fA;
mA.unlock();
lock_guard<mutex> lock{coutMutex};
cout << "Thread D: fA = " << _4 << ", fB = " << _3 << endl;
} };
A.join(); B.join(); C.join(); D.join();
}
合法打印
Thread C: fA = 1, fB = 0
Thread D: fA = 0, fB = 1
根据C ++标准?
注意:可以使用std::atomic<bool>
变量使用顺序一致的内存顺序或获取/释放内存顺序来实现自旋锁。所以问题是std::mutex
是否表现为顺序一致的自旋锁或获取/释放内存顺序自旋锁。
答案 0 :(得分:5)
是的,这是允许的,因此:不,std::mutex
不一定是顺序一致的。
std::mutex
未在标准中定义为顺序一致,仅为
30.4.1.2互斥体类型[thread.mutex.requirements.mutex]
11同步:对同一对象的事先解锁()操作应该 与(1.10)此操作同步 [lock()] 。
Synchronize-with 似乎与std::memory_order::release/acquire
相同[见this question)。
据我所知,获取/释放螺旋锁将满足std :: mutex的标准。
答案 1 :(得分:0)
是否有可能观察到fA和fB的不同 订单在不同的线程C和D?
“获取”解锁的“释放”状态(和副作用历史记录)的锁的基本思想使之成为不可能:您承诺仅通过获取相应的锁来访问共享对象,并且该锁将“同步”。 ”,并通过执行解锁的线程查看所有过去的修改。因此,只能存在一个历史记录,不仅是关于解锁操作的历史记录,而且还存在访问共享对象的历史记录。