C语言中,通过函数调用进行静态初始化是否线程安全?

3

想象一下:

void *ImCalledByThreads (/*...*/)
{
    //some stuff
    static typePlaceholder AmIThreadSafe = QuestionTag();
    //other stuff
}

这个初始化过程线程安全吗?

即使QuestionTag()是线程安全的,如果第一个线程运行了该函数并且另一个线程调用了此行代码,会发生什么?是否会检测到该函数只会执行一次?还是说对于多线程来说,这只是一个不好的想法?


2
这不是合法的C代码。但是,如果你谈论的是C++而不是C,那么几乎肯定不是线程安全的。我不确定C++11的规定,但是C++03以及之前的版本根本没有提到线程。从我查看过的各种编译器生成的代码中可以看出,它们在变量初始化周围并未添加任何同步原语。 - Adam Rosenfield
1
@AdamRosenfield 在gcc(c++)中它是线程安全的一段时间了,C++11则要求它必须是线程安全的。 - nos
2
这不是重复问题,因为我没有询问关于C++的内容。 - dhein
@nos:说得好,我的记忆有点模糊。我的当前版本的G++和Clang在C++03模式下操作时都会在静态初始化器周围插入适当的锁定。 - Adam Rosenfield
@Zaibis:抱歉,我搞混了语言。在C语言中,静态初始化器只能是常量表达式,因此没有什么可以保证线程安全的。 - Kerrek SB
显示剩余3条评论
1个回答

3
这并不是合法的C代码,因为C要求静态变量的初始化器为编译时常量。因此初始化可以在程序加载时发生,在任何线程启动之前,因此没有竞态条件。
来自于C99 §6.7.8/4:
“具有静态存储期限的对象的初始化器中的所有表达式都必须是常量表达式或字符串字面值。”
Visual Studio可能允许非常量作为非标准扩展名,但是对于它而言,无法预测结果。请查看其文档和/或其生成的汇编代码,以查看它是否线程安全。
对于C ++,其中允许非常量初始值设定项,请参见问题Is initialization of local static function-object thread-safe?。简单回答:在C++11中是,而在C++03及更早版本中不是(标准中没有提到线程),尽管编译器仍然可以选择使其线程安全。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接