静态const变量是否是线程安全的?

时间:2010-07-13 11:14:03

标签: c multithreading

我想知道静态常量变量是否是线程安全的?

示例代码段:

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

5 个答案:

答案 0 :(得分:16)

任何永远不会被修改的变量,无论它是否显式声明为const,都具有固有的线程安全性。

const不是编译器保证变量是不可变的保证。 const对编译器做出的承诺,即永远不会修改变量。如果你回到那个承诺,编译器会产生一个指向你的错误,但你总是可以通过抛弃constness来使编译器沉默。

答案 1 :(得分:13)

要真的安全,你应该做

static char const*const a[]

这会禁止修改数据要修改的表中的所有指针。

顺便说一句,我更喜欢在类型名后写const,以便乍一看const适用的位置,即它的左侧。

答案 2 :(得分:6)

在您的示例中,指针本身可以被视为线程安全。它将被初始化一次,以后不会被修改。

但是,指向的内存内容根本不是线程安全的。

答案 3 :(得分:3)

在此示例中,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

答案 4 :(得分:3)

  

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

在C中始终是线程安全的:sructures已经在编译时创建,因此在运行时不会采取额外的操作,因此不可能出现竞争条件。

请注意C ++兼容性。静态const对象将在函数的第一个条目初始化,但初始化不保证语言是线程安全的。 IOW这是一个竞争条件,当两个不同的线程同时进入函数并尝试并行初始化对象时。

但即使在C ++中,POD(普通旧数据:不使用C ++功能的结构,如您的示例中)也会以C兼容的方式运行。