Подтвердить что ты не робот

Переменные С++ 11 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
}

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

4b9b3361

Ответ 1

В соответствии со стандартом С++

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

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

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, имеют поток срок хранения. Хранилище для этих объектов должно продолжительность потока, в котором они созданы. Существует четкое объект или ссылка на поток, а использование объявленного имени относится к объект, связанный с текущим потоком

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

Ответ 2

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

Ответ 3

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

Per 9.2/6:

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

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

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

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

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

Нет.

Ответ 4

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

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

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

static X * pointer = new X;

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

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

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

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