多线程局部静态变量的初始化,需不需要同步,该怎么处理
多线程局部静态变量的初始化,需不需要同步
一个函数内部的静态类对象,因为静态变量是第一次使用的时候初始化的,如果多线程调用这个函数,静态变量初始化会不会出问题?
------解决思路----------------------
按标准来说,会
你可以学boost,在干正事前先做好
------解决思路----------------------
局部静态变量的初始化是安全的,如果编译器有Bug除外。
如果不放心,就改成全局的吧,让它提前初始化。
------解决思路----------------------
If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization
太多的静态的、需要初始化代码的、初始化代码彼此相关的对象总是很麻烦的。这种对象越少越好,而且构造函数要最小化。
------解决思路----------------------
楼上说的是C++11,03中还没有加入这段文字。
以前的标准都没有规定局部静态变量的初始化在并发模式下是否安全,于是编译器们纷纷偷懒,完全不去处理它的并发安全问题。
因此,多线程程序最好不要用需要明显初始化的局部静态变量,或者给构造函数加锁,构造函数中检查并设置初始化标置,依据标置决定是否需要进行初始化。不要担心加锁会影响效率,因为只有最初调用该函数的时候才会执行这段构造函数。构造成功后,系统不会再进行对象构造。系统判断静态对象是否已经构造的代码和你加锁并初始化的代码正好构成一个“双检测锁定”。
如果这个类有不可重复初始化的基类、不可重复初始化的成员对象,或这个类还会在其它地方以非静态的方式大量使用,那么使用指针。写一个新类把它包装起来,其中一个成员是原来那个类的指针类型,新类的构造函数加锁,然后判断指针是否为空(静态变量初始值必然是全0),并在堆中创建对象。
注意加锁时最好用命名的互斥量,以免不同线程进入函数时各创建一个不同的锁,导致锁定失去作用。
------解决思路----------------------
当我们声明一个静态局部变量时,系统本身就会创建一个附加的静态变量,用来标示静态变量是否被初始化,并且在进入函数之后的代码中做了一些附加的事。
要让它实现“初始化时其它进入的线程等待”,只要在这些附加的事中再加入一些代码就可以了。比如读写锁、双检测锁定、原子操作的标志加Event等等,由编译器去选择代价最低的手段就行了。
------解决思路----------------------
用户自己的同步代码不应该也没有能力去控制静态对象的初始化,只能去控制静态对象的访问,所以不会冲突。
而正因为用户没有办法为静态变量的初始化过程增加同步控制,这一语言特性是很重要的——除非决定将静态变量列为“兼容但会被放弃”的语言内容。
当然你也可以选择在构造函数中加锁,但编译器不需要去理睬你的锁,这个锁将注定无法起到效果——编译器已经保证不会有多个线程同时进入这个构造函数中。
------解决思路----------------------
需要同步,因为有竞争,可以使用tsl或者以下方法
------解决思路----------------------
会出问题,尚未初始化时,多线程竞速初始化,可能初始化多次。
解决办法:在子线程创建前,在主线程中调用一次以完成初始化。
你的加锁办法有损效率。
一个函数内部的静态类对象,因为静态变量是第一次使用的时候初始化的,如果多线程调用这个函数,静态变量初始化会不会出问题?
------解决思路----------------------
按标准来说,会
你可以学boost,在干正事前先做好
------解决思路----------------------
局部静态变量的初始化是安全的,如果编译器有Bug除外。
如果不放心,就改成全局的吧,让它提前初始化。
------解决思路----------------------
If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization
太多的静态的、需要初始化代码的、初始化代码彼此相关的对象总是很麻烦的。这种对象越少越好,而且构造函数要最小化。
------解决思路----------------------
楼上说的是C++11,03中还没有加入这段文字。
以前的标准都没有规定局部静态变量的初始化在并发模式下是否安全,于是编译器们纷纷偷懒,完全不去处理它的并发安全问题。
因此,多线程程序最好不要用需要明显初始化的局部静态变量,或者给构造函数加锁,构造函数中检查并设置初始化标置,依据标置决定是否需要进行初始化。不要担心加锁会影响效率,因为只有最初调用该函数的时候才会执行这段构造函数。构造成功后,系统不会再进行对象构造。系统判断静态对象是否已经构造的代码和你加锁并初始化的代码正好构成一个“双检测锁定”。
如果这个类有不可重复初始化的基类、不可重复初始化的成员对象,或这个类还会在其它地方以非静态的方式大量使用,那么使用指针。写一个新类把它包装起来,其中一个成员是原来那个类的指针类型,新类的构造函数加锁,然后判断指针是否为空(静态变量初始值必然是全0),并在堆中创建对象。
注意加锁时最好用命名的互斥量,以免不同线程进入函数时各创建一个不同的锁,导致锁定失去作用。
------解决思路----------------------
当我们声明一个静态局部变量时,系统本身就会创建一个附加的静态变量,用来标示静态变量是否被初始化,并且在进入函数之后的代码中做了一些附加的事。
要让它实现“初始化时其它进入的线程等待”,只要在这些附加的事中再加入一些代码就可以了。比如读写锁、双检测锁定、原子操作的标志加Event等等,由编译器去选择代价最低的手段就行了。
------解决思路----------------------
用户自己的同步代码不应该也没有能力去控制静态对象的初始化,只能去控制静态对象的访问,所以不会冲突。
而正因为用户没有办法为静态变量的初始化过程增加同步控制,这一语言特性是很重要的——除非决定将静态变量列为“兼容但会被放弃”的语言内容。
当然你也可以选择在构造函数中加锁,但编译器不需要去理睬你的锁,这个锁将注定无法起到效果——编译器已经保证不会有多个线程同时进入这个构造函数中。
------解决思路----------------------
需要同步,因为有竞争,可以使用tsl或者以下方法
void foo()
{
static std::string* pConfig = 0;
if(!p)
{
lock theLock;
if(!p)
{
static std::string config = "hello";
pConfig = &config;
}
}
//...
//pConfig is correctly created
}
------解决思路----------------------
会出问题,尚未初始化时,多线程竞速初始化,可能初始化多次。
解决办法:在子线程创建前,在主线程中调用一次以完成初始化。
你的加锁办法有损效率。