Являются ли переменные thread_local в C ++ 11 автоматически статическими?

Есть ли разница между этими двумя сегментами кода:

void f() {
thread_local vector<int> V;
V.clear();
... // use V as a temporary variable
}

а также

void f() {
static thread_local vector<int> V;
V.clear();
... // use V as a temporary variable
}

Предыстория: изначально у меня был вектор STATIC V (для хранения некоторых промежуточных значений, он очищается каждый раз, когда я вхожу в функцию) и однопоточная программа. Я хочу превратить программу в многопоточную, поэтому каким-то образом мне нужно избавиться от этого статического модификатора. Моя идея состоит в том, чтобы превратить каждую статику в thread_local и не беспокоиться ни о чем другом? Может ли такой подход иметь неприятные последствия?

62

Решение

Согласно стандарту C ++

Когда thread_local применяется к переменной области видимости блока,
статический спецификатор класса хранения подразумевается если он не появляется
эксплицитно

Значит, это определение

void f() {
thread_local vector<int> V;
V.clear();
... // use V as a temporary variable
}

эквивалентно

void f() {
static thread_local vector<int> V;
V.clear();
... // use V as a temporary variable
}

Тем не менее, статическая переменная не такой же, как переменная thread_local.

1 Все переменные, объявленные с ключевым словом thread_local, имеют поток
срок хранения. Хранение этих объектов должно продолжаться в течение
продолжительность потока, в котором они созданы. Есть отчетливый
объект или ссылка на поток, а использование объявленного имени относится к
объект, связанный с текущим потоком

Чтобы различать эти переменные, стандарт вводит новый термин продолжительность хранения потока наряду со статической продолжительностью хранения.

70

Другие решения

Да, «локальное хранилище потока» очень похоже на «глобальное» (или «статическое хранилище»), только вместо «длительности всей программы» у вас есть «длительность всего потока». Таким образом, блочная локальная переменная потока инициализируется при первом прохождении контроля через его объявление, но отдельно в каждом потоке, и уничтожается по окончании потока.

12

При использовании с thread_local, static подразумевается в области видимости блока (см. ответ @ Влада), требуется для участника класса; Я думаю, означает связь для области имен пространства.

Согласно 9.2 / 6:

В пределах определения класса
элемент не должен быть объявлен с помощью спецификатора класса памяти thread_local, если только он не объявлен как статический

Чтобы ответить на оригинальный вопрос:

Являются ли переменные thread_local в C ++ 11 автоматически статическими?

Здесь нет выбора, кроме переменных пространства имен.

Есть ли разница между этими двумя сегментами кода:

Нет.

4

Локальное хранилище потоков статично, но ведет себя совершенно иначе, чем простое статическое хранилище.

Когда вы объявляете переменную static, существует ровно один экземпляр переменной. Система компилятора / среды выполнения гарантирует, что она будет инициализирована для вас когда-то перед тем, как вы на самом деле ее используете, без указания точного времени (некоторые детали здесь опущены.)

C ++ 11 гарантирует, что эта инициализация будет потокобезопасной, однако до C ++ 11 эта безопасность потоков не гарантировалась. Например

static X * pointer = new X;

может привести к утечке экземпляров X, если более одного потока одновременно попадут в код статической инициализации.

Когда вы объявляете переменную thread local, существует потенциально много экземпляров переменной. Вы можете думать о них как о карте, которая была проиндексирована по идентификатору потока. Это означает, что каждый поток видит свою собственную копию переменной.

Еще раз, если переменная инициализируется, система компилятора / среды выполнения гарантирует, что эта инициализация произойдет до того, как будут использованы данные, и что инициализация произойдет для каждого потока, который использует переменную. Компилятор также гарантирует, что инициализация будет поточно-ориентированной.

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

3
По вопросам рекламы [email protected]