Являются ли функции статических переменных потокобезопасными в GCC?

В примере кода

void foo()
{
  static Bar b;
  ...
}

скомпилированный с GCC, гарантировано, что b будет создан и инициализирован поточно-безопасным способом?

На странице gcc man найдите опцию командной строки -fno-threadsafe-statics:

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

  • Означает ли это, что локальная статика по умолчанию защищена потоками GCC? Поэтому нет оснований для явной защиты, например. с pthread_mutex_lock/unlock?

  • Как написать переносимый код - как проверить, добавит ли компилятор его охранники? Или лучше отключить эту функцию GCC?

Ответ 1

  • Нет, это означает, что инициализация локального static является потокобезопасной.

  • Вы определенно хотите оставить эту функцию включенной. Инициализация потоков локальных static очень важна. Если вам нужен потокобезопасный доступ к локальному static, вам нужно будет добавить соответствующие защитники самостоятельно.

Ответ 2

У нас были серьезные проблемы с кодом блокировки, сгенерированным GCC 3.4, для защиты локальной статической инициализации. Эта версия использовала глобальный общий мьютекс для защиты всех и любой статической инициализации, которые приводят к тупиковой ситуации в нашем коде. У нас была локальная статическая переменная, инициализированная из результата функции, которая начала другой поток, который создал локальную статическую переменную. Псевдокод:

voif f()
{
  static int someValue = complexFunction();
  ...
}
int complexFunction()
{
  start_thread( threadFunc() );
  wait_for_some_input_from_new_thread();
  return input_from_new_thread;
}
void threadFunc()
{
  static SomeClass s();
  ...
}

Единственным решением было отключить эту функцию gcc. Если вам нужен переносимый код, который мы сделали, вы не можете в любом случае зависеть от функции, добавленной в конкретную версию gcc для обеспечения безопасности потоков. Предположительно, С++ 0x добавляет поточную локальную статистику, до тех пор это нестандартная магия, которая делает ваш код не переносимым, поэтому я советую против него. Если вы решите использовать его, я предлагаю вам проверить, что ваша версия gcc не использует один глобальный мьютекс для этой цели, написав пример приложения. (Трудность защиты потоков очевидна из-за того, что даже gcc не может понять это правильно)

Ответ 3

Это на самом деле не отвечает на ваши вопросы сразу (Charles уже сделал это), но я думаю, что пришло время опубликовать ссылку на в этой статье. Он проливает свет на инициализацию глобалов и должен быть прочитан и понят всем, кто пытается использовать переменные static в многопоточной среде.

Ответ 4

Я думаю, что ключевая фраза

... потокобезопасная инициализация локальная статика.

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