ThreadLocalStorage

class ThreadLocalStorage {

 public:

 

  // Prototype for the TLS destructor function, which can be optionally used to

  // cleanup thread local storage on thread exit.  'value' is the data that is

  // stored in thread local storage.

  typedef void (*TLSDestructorFunc)(void* value);

 

  // A key representing one value stored in TLS.

  class Slot {

   public:

    Slot(TLSDestructorFunc destructor = NULL);

 

    // This constructor should be used for statics.

    // It returns an uninitialized Slot.

    explicit Slot(base::LinkerInitialized x) {}

 

    // Set up the TLS slot.  Called by the constructor.

    // 'destructor' is a pointer to a function to perform per-thread cleanup of

    // this object.  If set to NULL, no cleanup is done for this TLS slot.

    // Returns false on error.

    bool Initialize(TLSDestructorFunc destructor);

 

    // Free a previously allocated TLS 'slot'.

    // If a destructor was set for this slot, removes

    // the destructor so that remaining threads exiting

    // will not free data.

    void Free();

 

    // Get the thread-local value stored in slot 'slot'.

    // Values are guaranteed to initially be zero.

    void* Get() const;

 

    // Set the thread-local value stored in slot 'slot' to

    // value 'value'.

    void Set(void* value);

 

    bool initialized() const { return initialized_; }

 

   private:

    // The internals of this struct should be considered private.

    bool initialized_;

#if defined(OS_WIN)

    int slot_;

#elif defined(OS_POSIX)

    pthread_key_t key_;

#endif

 

    DISALLOW_COPY_AND_ASSIGN(Slot);

  };

 

#if defined(OS_WIN)

  // Function called when on thread exit to call TLS

  // destructor functions.  This function is used internally.

  static void ThreadExit();

 

 private:

  // Function to lazily initialize our thread local storage.

  static void **Initialize();

 

 private:

  // The maximum number of 'slots' in our thread local storage stack.

  // For now, this is fixed.  We could either increase statically, or

  // we could make it dynamic in the future.

  static const int kThreadLocalStorageSize = 64;

 

  static long tls_key_;

  static long tls_max_;

  static TLSDestructorFunc tls_destructors_[kThreadLocalStorageSize];

#endif  // OS_WIN

 

  DISALLOW_COPY_AND_ASSIGN(ThreadLocalStorage);

};

 

// Temporary backwards-compatible name.

// TODO(evanm): replace all usage of TLSSlot.

typedef ThreadLocalStorage::Slot TLSSlot;

ThreadLocalStorage::TLSDestructorFunc
  ThreadLocalStorage::tls_destructors_[kThreadLocalStorageSize];
void** ThreadLocalStorage::Initialize() {
  if (tls_key_ == TLS_OUT_OF_INDEXES) {
    long value = TlsAlloc();
    DCHECK(value != TLS_OUT_OF_INDEXES);
    // Atomically test-and-set the tls_key.  If the key is TLS_OUT_OF_INDEXES,
    // go ahead and set it.  Otherwise, do nothing, as another
    // thread already did our dirty work.
    if (InterlockedCompareExchange(&tls_key_, value, TLS_OUT_OF_INDEXES) !=
            TLS_OUT_OF_INDEXES) {
      // We've been shortcut. Another thread replaced tls_key_ first so we need
      // to destroy our index and use the one the other thread got first.
      TlsFree(value);
    }
  }
  DCHECK(TlsGetValue(tls_key_) == NULL);
  // Create an array to store our data.
  void** tls_data = new void*[kThreadLocalStorageSize];
  memset(tls_data, 0, sizeof(void*[kThreadLocalStorageSize]));
  TlsSetValue(tls_key_, tls_data);
  return tls_data;
}
ThreadLocalStorage::Slot::Slot(TLSDestructorFunc destructor)
    : initialized_(false) {
  Initialize(destructor);
}
bool ThreadLocalStorage::Slot::Initialize(TLSDestructorFunc destructor) {
  if (tls_key_ == TLS_OUT_OF_INDEXES || !TlsGetValue(tls_key_))
    ThreadLocalStorage::Initialize();
  // Grab a new slot.
  slot_ = InterlockedIncrement(&tls_max_) - 1;
  if (slot_ >= kThreadLocalStorageSize) {
    NOTREACHED();
    return false;
  }
  // Setup our destructor.
  tls_destructors_[slot_] = destructor;
  initialized_ = true;
  return true;
}
void ThreadLocalStorage::Slot::Free() {
  // At this time, we don't reclaim old indices for TLS slots.
  // So all we need to do is wipe the destructor.
  tls_destructors_[slot_] = NULL;
  initialized_ = false;
}
void* ThreadLocalStorage::Slot::Get() const {
  void** tls_data = static_cast<void**>(TlsGetValue(tls_key_));
  if (!tls_data)
    tls_data = ThreadLocalStorage::Initialize();
  DCHECK(slot_ >= 0 && slot_ < kThreadLocalStorageSize);
  return tls_data[slot_];
}
void ThreadLocalStorage::Slot::Set(void* value) {
  void** tls_data = static_cast<void**>(TlsGetValue(tls_key_));
  if (!tls_data)
    tls_data = ThreadLocalStorage::Initialize();
  DCHECK(slot_ >= 0 && slot_ < kThreadLocalStorageSize);
  tls_data[slot_] = value;
}
void ThreadLocalStorage::ThreadExit() {
  if (tls_key_ == TLS_OUT_OF_INDEXES)
    return;
  void** tls_data = static_cast<void**>(TlsGetValue(tls_key_));
  // Maybe we have never initialized TLS for this thread.
  if (!tls_data)
    return;
  for (int slot = 0; slot < tls_max_; slot++) {
    if (tls_destructors_[slot] != NULL) {
      void* value = tls_data[slot];
      tls_destructors_[slot](value);
    }
  }
  delete[] tls_data;
  // In case there are other "onexit" handlers...
  TlsSetValue(tls_key_, NULL);
}
// Thread Termination Callbacks.
// Windows doesn't support a per-thread destructor with its
// TLS primitives.  So, we build it manually by inserting a
// function to be called on each thread's exit.
// This magic is from http://www.codeproject.com/threads/tls.asp
// and it works for VC++ 7.0 and later.
#ifdef _WIN64
// This makes the linker create the TLS directory if it's not already
// there.  (e.g. if __declspec(thread) is not used).
#pragma comment(linker, "/INCLUDE:_tls_used")
#else  // _WIN64
// This makes the linker create the TLS directory if it's not already
// there.  (e.g. if __declspec(thread) is not used).
#pragma comment(linker, "/INCLUDE:__tls_used")
#endif  // _WIN64
// Static callback function to call with each thread termination.
void NTAPI OnThreadExit(PVOID module, DWORD reason, PVOID reserved)
{
  // On XP SP0 & SP1, the DLL_PROCESS_ATTACH is never seen. It is sent on SP2+
  // and on W2K and W2K3. So don't assume it is sent.
  if (DLL_THREAD_DETACH == reason || DLL_PROCESS_DETACH == reason)
    ThreadLocalStorage::ThreadExit();
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值