Скажи у меня две темы 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
ведет себя как последовательно согласованная спин-блокировка или спин-блокировка порядка получения / освобождения памяти.
Да, это разрешено, поэтому: нет, std::mutex
не обязательно последовательно последовательно.
std::mutex
не определено в стандарте, чтобы быть последовательно последовательным, только то, что
30.4.1.2 Типы мьютекса [thread.mutex.requirements.mutex]
11 Синхронизация: до операции unlock () над одним и тем же объектом
синхронизировать с (1.10) эту операцию [замок()].
Синхронизировать-с кажется, определен в том же был std::memory_order::release/acquire
(увидеть этот вопрос).
Насколько я вижу, спин-блокировка получения / выпуска будет соответствовать стандартам для std :: mutex.
Других решений пока нет …