从C ++ 11开始,静态变量初始化保证是线程安全的。但是如何在多个线程中修改静态变量呢?如下所示
static int initialized = 0;
Initialize()
{
if (initialized)
return;
initialized = 1; // Is this thread safe?
}
我问这个问题的原因是我正在阅读源代码
Py_Initialize()
,我试图将Python嵌入到多线程C ++应用程序中,我想知道在多个线程中多次调用Py_Initialize()
是否安全? Py_Initialize()
的实施可归结为
函数_Py_InitializeEx_Private
,如下所示
// pylifecycle.c
static int initialized = 0;
_Py_InitializeEx_Private(int install_sigs, int install_importlib)
{
if (initialized)
return;
initialized = 1;
// a bunch of other stuff
}
C的结论与C ++相同吗?
修改 所以所有答案都很好,我选择的是最清楚我的头脑。
答案 0 :(得分:4)
修改静态变量不是线程安全的,但初始化静态变量是线程安全的。所以你可以这样做:
void my_py_init() {
static bool x = (Py_Initialize(), true);
}
那就是它。您现在可以根据需要从多个线程中调用my_py_init
,Py_Initialize
只会被调用一次。
答案 1 :(得分:2)
Py_Initialize
不是线程安全的。只有当你知道Python解释器已经被初始化时,你才可以从多个线程调用它,但如果你能证明调用函数是愚蠢的。
实际上,大多数Python C-API调用都不是线程安全的;您需要获取全局解释器锁(GIL)才能与Python解释器进行交互。 (有关详细信息,请参阅Python C-API docs。请仔细阅读。)
但是,据我所知,在初始化解释器之前,您无法使用标准API来获取GIL。因此,如果您有多个线程,其中任何一个可能初始化相同的Python解释器,您需要使用自己的互斥锁来保护对Py_Initialize
的调用。如果可以使用程序逻辑,那么在启动任何线程之前,最好先进行一次初始化。
您引用的代码:
static int initialized = 0;
void Initialize_If_Necessary()
{
if (initialized)
return;
initialized = 1;
// Do the initialization only once
}
即使initialized
是原子类型,显然不是任何语言的线程安全。假设两个线程在发生任何初始化之前同时执行此代码:它们都将initialized
视为false,因此它们都继续初始化。 (如果您没有两个核心,您可以想象第一个进程是在initialized
的测试和分配之间切换的任务。)
答案 2 :(得分:1)
跨多个线程修改静态变量是不安全的,因为如果将变量放入寄存器中,那么其他内核就会被安排。相同寄存器中的信息将不同(修改另一个线程中的变量将与尝试访问该核心的寄存器版本相同,其中包含完全不同的数据)。