В частности, я хочу установить значение указателя функции. Для простоты я хочу делать это много раз, из нескольких потоков, но всегда простым способом, например:
typedef void (*F)();
F f = 0;
void foo()
{
}
// called many times from multiple threads
void set()
{
f = &foo;
}
int main()
{
set(); // also other threads can invoke it at any time
f();
return 0;
}
Таким образом, изначально указатель на функцию равен NULL, а затем становится & foo, когда код выполняется в первый раз. Интересно, может ли из-за какой-либо неатомной операции записи нарушиться указатель функции.
Гарантируется, что он будет прочитан впервые после установки.
РЕДАКТИРОВАТЬ: уточняю:
- Основная причина, по которой я использую указатель на функцию, - это удаление некоторых зависимостей между модулями. Это маленький элемент большого реального проекта. Я действительно не могу напрямую вызвать foo.
- Я знаю, как программировать, и мне не нужна базовая информация о таких вещах, как мьютекс. У меня вопрос, безопасно ли это БЕЗ мьютекса.
- В коде гарантируется, что никакой другой поток не устанавливает указатель ни на что иное, кроме & foo.
3 ответа
Стандарт говорит, что ваш код вызывает неопределенное поведение. Но в вашем конкретном случае, то есть с вашим конкретным компилятором и архитектурой, ваш код действительно может быть без проблем. Итак, с теоретической точки зрения, ваш код не в порядке. С практической точки зрения ответ зависит от вашего конкретного случая и ни в коем случае не является общим. Лично я предлагаю заменить F f = 0;
на std::atomic<F> f(0);
, чтобы код гарантированно был в порядке во всех случаях.
Просто чтобы проиллюстрировать случай, когда ваш код ломается: реализация может очистить цель перед каждой операцией записи. Такая реализация законна и соответствует стандарту, хотя и не обязательно отмечена наградами :)
Я думаю, что это скорее проблема синхронизации потоков, чем проблема, связанная с C ++. Ответ на ваш вопрос: да, вы можете безопасно записать значение в переменную / указатель на С ++ (не уверен, что вы имеете в виду под константой; мне кажется, что вы просто хотите назначить указатель на функцию ), вам просто нужно использовать взаимное исключение , чтобы потоки не перезаписывали значение, когда вы не хотите, чтобы они
В зависимости от того, чего вы в конечном итоге хотите достичь, вам может понадобиться более одного мьютекса (например, если вы хотите обеспечить определенный порядок, в котором потоки назначают указатель на функцию), но это определенно способ безопасно сделать это.
Рассматривали ли вы возможность использования std::mutex
и std::lock_guard
для обеспечения безопасности потоков?
Например
{
std::lock_guard<std::mutex> lg(my_mutex);
f = &foo;
// then use f to perform your operation
}
После закрывающей скобки lock_guard
выпадает из области видимости и разблокирует ваш mutex
. Это означает, что тот, кто устанавливает f
, может безопасно использовать этот указатель на функцию, зная, что другой поток не изменил указатель функции между его установкой и попыткой его использования.
Похожие вопросы
Связанные вопросы
Новые вопросы
c++
C++ — это язык программирования общего назначения. Изначально он разрабатывался как расширение C и имел аналогичный синтаксис, но теперь это совершенно другой язык. Используйте этот тег для вопросов о коде, который будет скомпилирован с помощью компилятора C++. Используйте тег версии для вопросов, связанных с конкретной стандартной версией [C++11], [C++14], [C++17], [C++20] или [C++23]. и т.д.