【发布时间】:2010-07-13 11:14:03
【问题描述】:
我想知道静态常量变量是否是线程安全的?
示例代码sn-p:
void foo(int n)
{
static const char *a[] = {"foo","bar","egg","spam"};
if( ... ) {
...
}
}
【问题讨论】:
标签: c multithreading
我想知道静态常量变量是否是线程安全的?
示例代码sn-p:
void foo(int n)
{
static const char *a[] = {"foo","bar","egg","spam"};
if( ... ) {
...
}
}
【问题讨论】:
标签: c multithreading
任何从未修改过的变量,无论它是否显式声明为 const,本质上都是线程安全的。
const 不是编译器保证变量不可变的保证。 const 是 您 向编译器作出的承诺,即永远不会修改变量。如果你违背这个承诺,编译器会生成一个错误提示你,但你总是可以通过抛弃 constness 来使编译器静音。
【讨论】:
为了安全起见,你应该这样做
static char const*const a[]
这禁止修改数据和要修改的表中的所有指针。
顺便说一句,我更喜欢在类型名之后写const,这样一目了然const 的应用位置,即它的左侧。
【讨论】:
在您的示例中,指针本身可以被视为线程安全的。它会被初始化一次,以后不会被修改。
但是,指向的内存内容根本不是线程安全的。
【讨论】:
在此示例中,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";
您可以通过以下方式访问nth 字符串:
const char *s;
for (i=0, s=a; i<n && *s; s+=strlen(s)+1);
return s;
请注意,最后的 \0 很重要。它使字符串末尾有两个 0 字节,因此如果 n 超出范围,则停止循环。或者,您可以提前对n 进行边界检查。
【讨论】:
static const char *a[] = {"foo","bar","egg","spam"};
在 C 中始终是线程安全的:结构在编译时已经创建,因此在运行时不会采取额外的操作,因此不可能出现竞争条件。
但请注意 C++ 兼容性。静态 const 对象将在第一次进入函数时被初始化,但语言不保证初始化是线程安全的。 IOW 当两个不同的线程同时进入函数并尝试并行初始化对象时,这对竞争条件开放。
但即使在 C++ 中,POD(普通旧数据:不使用 C++ 特性的结构,如您的示例)也会以 C 兼容方式运行。
【讨论】:
a[0] = "faa",所以不,如果你提供一些额外的保证,这只是线程安全的,但这本身不是线程安全的。