Является ли std::move_only_function потокобезопасным?

Безопасно ли вызывать объект 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 всегда содержит действительную функцию.

Нет, потому что он не атомный. И он не использует атомарность.

Ahmed AEK 23.07.2024 18:15

В общем случае функция НЕ является потокобезопасной, если в ней явно не указано, что это так. (Из головы я знаю только то, что инициализация статической локальной переменной явно потокобезопасна) начиная с C++11

Pepijn Kramer 23.07.2024 18:59
Вот что говорит стандарт о потокобезопасности типов стандартных библиотек при отсутствии конкретной формулировки об обратном. Краткая версия: «Неконстантные методы могут изменять this, его параметры или что-либо, косвенно доступное через this или его параметры. Константные методы не могут ничего изменять». Вы вызываете неконстантные методы (operator()) в одном потоке, одновременно обращаясь к объекту из другого потока без синхронизации, что является гонкой данных.
Raymond Chen 23.07.2024 19:04
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
117
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Нет, это небезопасно.
Оператор присваивания (std::move_only_function::operator=) не обязательно является атомарным.
Поэтому вы можете иметь переключение контекста в середине, оставляя объект std::move_only_function в недопустимом состоянии, которое другой поток попытается вызвать, что приведет к неопределенному поведению.

std::move_only_function сам по себе не предоставляет гарантий безопасности потоков, вы можете безопасно использовать его в многопоточном контексте, если правильно обрабатываете синхронизацию и контроль доступа.

Самая большая проблема заключается в том, что если используется оптимизация небольшого буфера (а в MSVC его размер составляет 5 указателей), если ваша лямбда-выражение захватывает что-либо и оно было заменено во время работы функции, ваши текущие захваты лямбда-выражений будут повреждены.

Вы не только хотите, чтобы его назначение было потокобезопасным, вы также не хотите, чтобы оно переназначалось во время его работы, вы также захотите выйти из него перед его вызовом или заблокировать его блокировкой RW во время выполнения. выполняя его.

Лучшим вариантом будет использовать атомарный (общий) указатель на функцию только перемещения, если вам нужна потокобезопасность.

Другие вопросы по теме