Хочу разобраться в том, как работает std::call_once. И главное - lock-free ли он. Здесь пытаются его реализовать с использованием мьютекса. Если call_once можно реализовать только с использованием мьютекса, какие проблемы могут возникнуть с этим кодом?
#include
using namespace std;
using my_once_flag = atomic
void my_call_once(my_once_flag& flag, std::function
Ответ
Стандарт не налагает ограничений на реализацию std::call_once поэтому, его реализация может быть как с блокировками, так и без(я не знаю, возможно ли такую реализацию придумать).
Что касается Вашей реализации: она просто неверна. Пусть у нас будет 2 потока, которые одновременно заходят в функцию и попадают на строчку: flag.compare_exchange_strong один из них выставит флаг, а другой уйдёт с полной уверенностью, что функция уже была вызвана. Но до вызова функции дело ещё вообще не дошло! Поэтому, в правильной реализации, на входе в call_once все потоки должны выстроиться в очередь, если кто-то уже начал выполнение функции.
Конечно, если бы функция была «чистой»(pure) можно было бы устроить спекулятивное выполнение, с принятием результата от того потока, что первым закончит её исполнение. Но стандарт не налагает никаких ограничений на функцию, которая может быть исполнена в call_once. Поэтому, в целом, я не вижу как можно её реализовать в неблокирующем виде.
Комментариев нет:
Отправить комментарий