Являются ли встроенные функции в C / C++ способом сделать их потокобезопасными?
Я делаю следующие рассуждения, пожалуйста, скажите мне, что неправильно (или правильно) об этом:
"Если встраивание функции дублирует код в месте вызова функции, то статические и локальные переменные дублируются для каждой вызывающей ее функции, и если есть только один поток, выполняющий функцию, которая одновременно вызывает встроенную, то код является потокобезопасным".
" и, если это не помогает со статическими и глобальными переменными, делает это с кодом, который создает ли временные переменные?"
спасибо
11 ответов
когда вы объявляете функцию как встроенную, это просто подсказка компилятору. Статические переменные имеют четкое определение в языке. Если компилятор выполняет встроенную функцию, он по-прежнему обязан сохранять статические переменные общими для всех экземпляров функции. Поэтому они будут оставаться глобальными и должны быть защищены в среде MT.
Что касается локальных переменных, если они не используются вне функции, они являются потокобезопасными независимо от функция встроена или нет.
нет, вы ошибаетесь. Для статической переменной, является ли она встроенной или нет, существует только один экземпляр. Встроенные функции не влияют на безопасность резьбы, так или иначе.
каждый поток получает свою собственную копию локальных объектов, поэтому не может быть никаких связанных с потоками проблем с ними, независимо от того, делаете ли вы его встроенным или нет.
но если вы обращаетесь к статической или переменной-члену класса, все проблемы, связанные с многопоточностью (повреждение переменной, потерянное обновление...) по-прежнему будет там, независимо от того, является ли он встроенным или нет.
Inlining и безопасность резьбы ортогональны, т. е. несвязанные концепции.
рассмотрим эти функции:
int factorial(const int n) { if (n <= 1) { return 1; } return factorial(n - 1); }
эта функция не может быть встроена, так как она рекурсивна, но она совершенно потокобезопасна.
int factorial_2(int n) { int Result = 1; while (n > 1) { Result *= n--; } return Result; }
эта функция может быть встроена компилятором и по-прежнему полностью потокобезопасна.
int RefCount; void DecRef() { --RefCount; }
эта функция не является потокобезопасной независимо от того, содержит ли компилятор ее или нет.
предыдущие версии C++ (и текущая версия C) не признают концепцию потоков. Это просто не входит в стандарт. Поэтому полагаться на некоторую оптимизацию компилятора, чтобы сделать ваш код потокобезопасным, не очень хорошая идея.
есть (или, возможно,были) багги-компиляторы, которые дублируют статические переменные для каждой строки содержащей функции. Это не намеренное поведение.
с компилятором, совместимым со стандартом, вы гарантированно имеете один экземпляр каждой статической переменной независимо от вставки и должны сами заботиться о безопасности потоков.
потокобезопасность не имеет ничего общего с inlining. То, что каждый поток выполняет копию одного и того же кода, не делает безопасным доступ к общим данным. Пожалуйста, не забудьте прочитать на потокобезопасность перед началом многопоточного программирования.
на вашем месте я бы не использовал статические переменные внутри встроенных функций. Более старые версии стандарта C++ требовали другого значения, чем текущий.
вставка не влияет на то, является ли функция потокобезопасной. Например:
inline void doTheThing()
{
int a = 42; // this is thread safe, but it would be anyway
vector<int> * answers = getTheAnswers(); // this is not thread safe
}
доступ к вектору, на который указывает getTheAnswers (), не является потокобезопасным, потому что нет кода, препятствующего выполнению кода любым другим потоком. Создание функции inline не препятствует вызову doTheThing () несколькими потоками одновременно. Чтобы сделать dothething () потокобезопасным, вам нужно убедиться, что либо он не вызывается параллельно, либо любой общий (нелокальный) данных доступ защищен.
совсем нет.
чтобы быть потокобезопасной, функция должна быть потокобезопасной по отношению к любому экземпляру функции, включая саму себя; несколько потоков могут выполнять один и тот же экземпляр встроенной функции одновременно.
поэтому, даже если компилятор сделал то, что вы предложили (чего он не должен, как говорили другие), это все равно не сделает его потокобезопасным.
все статические переменные в (нормальных и встроенных) функциях переходят в кучу. Кучи НЕ ПОТОКОБЕЗОПАСНО.