Многопоточный ping-pong. Использовать memory_order_acquire / memory_order_release или memory_order_relaxed?
Имеется код пинг-понга (использую MSVC 2017).
Вопрос: является ли он корректным? или нужно использовать memory_order_acquire и memory_order_release?
При запуске он работает нормально.
#include <iostream>
#include <atomic>
#include <thread>
std::atomic<int> cur_thread_index = 0;
const int COUNT = 10;
void func(std::string text, int thread_index)
{
for(int i = 0; i < COUNT; ++i)
{
while(cur_thread_index.load(std::memory_order_relaxed) != thread_index){}
std::cout << text.c_str() << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
cur_thread_index.store(1 - thread_index, std::memory_order_relaxed);
}
}
int main()
{
std::thread t1(func, "ping", 0);
std::thread t2(func, "pong", 1);
t1.join();
t2.join();
return 0;
}
Ответы (1 шт):
Всё нормально. memory_order_relaxed говорит компилятору не добавлять барьер памяти при выполнении данной операции, а барьеры памяти имеет смысл добавлять только при работе более чем с одним разделяемым объектом: в таком случае результаты работы программы неотличимы от работы без барьера. Подробнее о том, что такое барьеры памяти смотри здесь.
Надо помнить, что x86 на уровне архитектуры не поддерживает ни какие расслабленные модели памяти и на нём в любом случае практически все* операции с атомарными переменными будут выполняться точно также как и операцииmemory_order_seq_cst. т.е. единственное, на что влияет этот параметр при компиляции под x86, на сколько свободно компилятор может переставлять вычисление операций.
* У меня нет полной уверенности, что это применимо абсолютно ко всем, хотя скорей всего это так