愚蠢的 SingletonThreadLocal 类使用两个“c11 thread_local”和一个“ThreadLocal”来支持快速访问和销毁依赖问题。
但我无法理解“thread_local 和 ThreadLocal”的破坏顺序。
FOLLY_EXPORT FOLLY_ALWAYS_INLINE static T& get() {
if (kIsMobile) {
return getWrapper();
}
static thread_local LocalCache cache;
return FOLLY_LIKELY(!!cache.cache) ? *cache.cache : getSlow(cache);
}
FOLLY_NOINLINE static Wrapper& getSlow(LocalCache& cache) {
if (threadlocal_detail::StaticMetaBase::dying()) {
return getWrapper();
}
static thread_local LocalLifetime lifetime;
lifetime.track(cache); // idempotent
return FOLLY_LIKELY(!!cache.cache) ? *cache.cache : getWrapper();
}
struct LocalLifetime {
~LocalLifetime() {
auto& wrapper = getWrapper();
auto& lifetimes = wrapper.lifetimes[this]; //1. thread wrapper may be destructed.
for (auto cache : lifetimes) {
auto const it = wrapper.caches.find(cache);
if (!--it->second) {
wrapper.caches.erase(it);
cache->cache = nullptr;
}
}
wrapper.lifetimes.erase(this);
}
...
}
struct Wrapper {
~Wrapper() {
for (auto& kvp : caches) { //cache may be destruct
kvp.first->cache = nullptr; //2. thread cache maybe destructed.
}
}
}
请查看评论 1、2. LocalLifetime LocalCache 的破坏顺序,而 ThreadLocal 是未定义的,代码可能会访问被破坏的内存,令人惊讶。