pthread_once 确保一个被注册的子函数至多被执行一次:
#include <pthread.h>
#include <cassert>
using namespace std;
class Singleton
{
public:
static
Singleton *instance();
private:
static
Singleton *instance_;
static
pthread_once_t once;
static
void _instance();
Singleton();
};
Singleton::Singleton()
{
};
Singleton *Singleton::instance_ = NULL;
void Singleton::_instance()
{
assert(NULL == instance_);
instance_ = new Singleton();
}
pthread_once_t Singleton::once = PTHREAD_ONCE_INIT;
Singleton *Singleton::instance()
{
pthread_once(&once, Singleton::_instance);
return instance_;
}
下面这段代码,看起来非常和谐的 double-check,what problem?
pthread_mutex_t singleton_mutex = PTHREAD_MUTEX_INITIALIZER;
Singleton *Singleton::instance2()
{
if (NULL == instance_) {
pthread_mutex_lock(&singleton_mutex);
if (NULL == instance_) {
instance_ = new Singleton();
}
pthread_mutex_unlock(&singleton_mutex);
}
return instance_;
}
悲剧在于,由于实现机制的原因,可能存在这一种情况,instance_ 指针先被赋值,而后执行 initializer,在这个初始化完成之前,对于另一个线程而言,这个指针看起来指向一个被初始化过的对象,错误地使用了这个变量!
参考这篇文章: 原子,锁,还有内存屏障 主要讨论指令乱序导致的问题;而这篇:Linux 内核中的内存屏障 讨论的是 cache line 导致的问题。
TO BE CONTINUED......