【发布时间】:2010-01-13 01:13:15
【问题描述】:
这是我刚刚想出的一个想法,它是一种安全、有效的方法来处理单例同步问题。它基本上是双重检查锁定,但有一个涉及线程本地存储的扭曲。在 Java/C#/D 风格的伪代码中,假设 __thread 表示静态变量的线程本地存储:
class MySingleton {
__thread static bool isInitialized;
static MySingleton instance;
static MySingleton getInstance() {
if(!isInitialized) {
synchronized {
isInitialized = true;
if(instance is null) {
instance = new MySingleton();
}
}
}
return instance;
}
}
这保证在程序的整个生命周期中每个线程只进入synchronized 块一次。从那时起,我们对线程局部布尔值进行简单检查,以查看我们是否已经进入同步块并验证对象是从该线程初始化的。
【问题讨论】:
-
我看不到线程存储给聚会带来的任何好处
-
在实践中,线程本地存储可能比简单的同步涉及更多的开销。
-
并且每个线程进入一次。
-
而且 TLS 通常比其他同步指令(甚至 cmpxchg 等)更快,如果它是编译器固有的 TLS(即使用 __thread 或 declspec(__thread) 或任何您的语言使用)。相反,像 pthreads 这样的通用 TLS 实现可能会更慢。查看来自 Google 的 Mike Burrows 的类似想法。 open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2444.html
-
即使是非内在线程本地存储也可能通常更快,因为它不涉及原子操作。在我的 Windows 机器上,TlsGetValue(),一个 Win32/64 API 调用在大约 7-8 个周期内返回,而单个 cmpxchg 指令大约需要 30 个周期。
标签: multithreading language-agnostic concurrency locking thread-safety