Являются ли статические переменные const поточно-ориентированными? - PullRequest
10 голосов
/ 13 июля 2010

Мне интересно, являются ли статические константы переменными потокобезопасными или нет?

Пример кода:

void foo(int n)
{
     static const char *a[] = {"foo","bar","egg","spam"};
     if( ... ) {
       ...
      }
}

Ответы [ 5 ]

16 голосов
/ 13 июля 2010

Любая переменная, которая никогда не изменяется, независимо от того, явно ли она объявлена ​​как const, является поточно-ориентированной.

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

13 голосов
/ 13 июля 2010

Чтобы быть в полной безопасности, вы должны сделать

static char const*const a[]

запрещает изменение данных и всех указателей в таблице, подлежащей изменению.

Кстати, я предпочитаю писать const после typename, чтобы на первый взгляд было ясно, где применяется const, а именно слева от него.

6 голосов
/ 13 июля 2010

В вашем примере сам указатель можно считать потокобезопасным. Он будет инициализирован один раз и не будет изменен позже.

Однако содержимое указанной памяти вообще не будет поточно-ориентированным.

3 голосов
/ 13 июля 2010

static const char * a [] = {"foo", "bar", "egg", "spam"};

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

Остерегайтесь совместимости с C ++. Статический объект const будет инициализирован при первом входе в функцию, но инициализация не гарантирует поточно-ориентированный язык. IOW это открыто для состояния гонки, когда два разных потока входят в функцию одновременно и пытаются инициализировать объект параллельно.

Но даже в C ++ POD (обычные старые данные: структуры, не использующие функции C ++, как в вашем примере) будут вести себя совместимым с C образом.

3 голосов
/ 13 июля 2010

В этом примере a не является const.Это массив указателей на const строки.Если вы хотите сделать a сам const, вам нужно:

static const char *const a[] = {"foo","bar","egg","spam"};

Независимо от того, const или нет, всегда безопасно для чтения данных из нескольких потоков.если вы не пишете в него ни от одного из них.

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

static const char a[][5] = {"foo","bar","egg","spam"};

, где 5 выбрано так, что все ваши струны подходят.Если строки имеют переменную длину и вам не нужен быстрый доступ к ним (например, если они являются сообщениями об ошибках для функции, такой как strerror для возврата), то хранение их таким образом является наиболее эффективным:

static const char a[] = "foo\0bar\0egg\0spam\0";

и вы можете получить доступ к n-й строке с помощью:

const char *s;
for (i=0, s=a; i<n && *s; s+=strlen(s)+1);
return s;

Обратите внимание, что конечный \0 важен.Это приводит к тому, что строка имеет два 0 байта в конце, тем самым останавливая цикл, если n выходит за пределы.В качестве альтернативы вы можете заранее проверить границы n.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...