Рассмотрим следующую программу:
int i{0};
std::experimental::barrier b{2};
int main()
{
std::thread t0{[] {
b.arrive_and_wait();
std::cout << i << '\n';
}};
std::thread t1{[] {
i = 2;
b.arrive_and_wait();
}};
t0.join();
t1.join();
}
Эта программа гарантированно распечатает 2
, даже если i
не является атомарной переменной?
В соответствии с cppreference:
Звонки в
arrive_and_wait
синхронизируется с началом фазы завершения барьера. Завершение фазы завершения синхронизируется с возвратом из вызова.Звонки в
arrive_and_drop
а такжеarrive_and_wait
никогда не вводите данные о гонках с собой или друг с другом.
Это говорит о том, что есть точка синхронизации на каждом arrive_and_wait
вызов. Однако я не уверен, разрешено ли компилятору переупорядочивать операции чтения / записи на i
, поскольку это не атомное.
Из того, что я понимаю из std :: барьерная ссылка(мой акцент):
Барьер имеет фазу завершения, которая выполняется одним из участвующих потоков, как только все потоки в наборе участвующих потоков достигают точки синхронизации. Вызовы receive_and_wait и Arrive_and_drop синхронизируются с началом фазы завершения; TКонец фазы завершения синхронизируется с возвратами всех вызовов, заблокированных его завершением..
Вы можете предположить, что все изменения, сделанные до барьера в разных потоках, видны в других потоках, даже если они не являются атомарными. Как эта ссылка указывает (мой акцент):
Между потоками оценка A происходит между потоками перед оценкой B, если выполняется любое из следующих условий
1) А синхронизируется с Б
2) A упорядочен по зависимости перед B
3) А синхронизируется — с некоторой оценкой X, а X — перед B
4) A секвенируется — до некоторой оценки X, а X inter-thread происходит — до B
5) Интерпоток происходит до некоторой оценки X, а X межпоток происходит до B
Других решений пока нет …