我想知道静态常量变量是否是线程安全的?
示例代码片段:
void foo(int n)
{
static const char *a[] = {"foo","bar","egg","spam"};
if( ... ) {
...
}
}
我想知道静态常量变量是否是线程安全的?
示例代码片段:
void foo(int n)
{
static const char *a[] = {"foo","bar","egg","spam"};
if( ... ) {
...
}
}
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";
您可以使用以下方式访问第n
个字符串:
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++的兼容性。静态常量对象会在第一次进入函数时初始化,但该初始化在语言上不能保证是线程安全的。也就是说,当两个不同的线程同时进入该函数并尝试并行初始化对象时,就会存在竞争条件。
但即使在C++中,POD(普通的旧数据:不使用C++特性的结构体,例如你的示例)也会像C语言那样表现。
a[0] = "faa"
的操作,因此,如果您提供一些额外的保证,那么这只有在给出某些额外保证的情况下才是线程安全的,但本质上这不是线程安全的。 - Jens Gustedt