我想知道静态常量变量是否是线程安全的?
示例代码段:
void foo(int n)
{
static const char *a[] = {"foo","bar","egg","spam"};
if( ... ) {
...
}
}
答案 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兼容的方式运行。