facebook folly SingletonThreadLocal surprising design

273 views Asked by At

folly SingletonThreadLocal class use two "c11 thread_local" and one "ThreadLocal" to support fast access and destruction dependency problems.

But I could not understand the destruction order of "thread_local and 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.
      }
    }
  }

please check the comment 1, 2. the destruction ordered of LocalLifetime LocalCache, and ThreadLocal is undefined, the code may access the destructed memory, it is surprising.

0

There are 0 answers