Безопасно ли вызывать объект std::move_only_function в одном потоке и заменять функцию, на которую он указывает, в другом потоке?
Мой код:
#include <future>
#include <functional>
int main() {
std::move_only_function<void()> fn = []{};
auto future1 = std::async(std::launch::async, [&]{ fn(); });
auto future2 = std::async(std::launch::async, [&]{ fn = []{}; });
future1.get();
future2.get();
}
Меня не волнует, будет ли вызываться старая или новая функция. Также я знаю, что fn всегда содержит действительную функцию.
В общем случае функция НЕ является потокобезопасной, если в ней явно не указано, что это так. (Из головы я знаю только то, что инициализация статической локальной переменной явно потокобезопасна) начиная с C++11
this, его параметры или что-либо, косвенно доступное через this или его параметры. Константные методы не могут ничего изменять». Вы вызываете неконстантные методы (operator()) в одном потоке, одновременно обращаясь к объекту из другого потока без синхронизации, что является гонкой данных.





Нет, это небезопасно.
Оператор присваивания (std::move_only_function::operator=) не обязательно является атомарным.
Поэтому вы можете иметь переключение контекста в середине, оставляя объект std::move_only_function в недопустимом состоянии, которое другой поток попытается вызвать, что приведет к неопределенному поведению.
std::move_only_function сам по себе не предоставляет гарантий безопасности потоков, вы можете безопасно использовать его в многопоточном контексте, если правильно обрабатываете синхронизацию и контроль доступа.
Самая большая проблема заключается в том, что если используется оптимизация небольшого буфера (а в MSVC его размер составляет 5 указателей), если ваша лямбда-выражение захватывает что-либо и оно было заменено во время работы функции, ваши текущие захваты лямбда-выражений будут повреждены.
Вы не только хотите, чтобы его назначение было потокобезопасным, вы также не хотите, чтобы оно переназначалось во время его работы, вы также захотите выйти из него перед его вызовом или заблокировать его блокировкой RW во время выполнения. выполняя его.
Лучшим вариантом будет использовать атомарный (общий) указатель на функцию только перемещения, если вам нужна потокобезопасность.
Нет, потому что он не атомный. И он не использует атомарность.