X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FThreadCachedInt.h;h=3ed53b20bacf584e1951c70f8dd49a5f2fa893f2;hb=b95919855a9053e9d7f425ba6595d369f055fbb0;hp=69c03d1f020ce7f5214f3eaf7d77c57c0b302125;hpb=5c77fedbef46995a71ffa268c9fcaf49efddd01b;p=folly.git diff --git a/folly/ThreadCachedInt.h b/folly/ThreadCachedInt.h index 69c03d1f..3ed53b20 100644 --- a/folly/ThreadCachedInt.h +++ b/folly/ThreadCachedInt.h @@ -1,5 +1,5 @@ /* - * Copyright 2013 Facebook, Inc. + * Copyright 2017 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,12 +20,14 @@ * @author Spencer Ahrens (sahrens) */ -#ifndef FOLLY_THREADCACHEDINT_H -#define FOLLY_THREADCACHEDINT_H +#pragma once #include -#include "folly/Likely.h" -#include "folly/ThreadLocal.h" + +#include + +#include +#include namespace folly { @@ -45,7 +47,7 @@ class ThreadCachedInt : boost::noncopyable { void increment(IntT inc) { auto cache = cache_.get(); - if (UNLIKELY(cache == NULL || cache->parent_ == NULL)) { + if (UNLIKELY(cache == nullptr)) { cache = new IntCache(*this); cache_.reset(cache); } @@ -61,8 +63,11 @@ class ThreadCachedInt : boost::noncopyable { // Reads the current value plus all the cached increments. Requires grabbing // a lock, so this is significantly slower than readFast(). IntT readFull() const { + // This could race with thread destruction and so the access lock should be + // acquired before reading the current value + auto accessor = cache_.accessAllThreads(); IntT ret = readFast(); - for (const auto& cache : cache_.accessAllThreads()) { + for (const auto& cache : accessor) { if (!cache.reset_.load(std::memory_order_acquire)) { ret += cache.val_.load(std::memory_order_relaxed); } @@ -80,8 +85,11 @@ class ThreadCachedInt : boost::noncopyable { // little off, however, but it should be much better than calling readFull() // and set(0) sequentially. IntT readFullAndReset() { + // This could race with thread destruction and so the access lock should be + // acquired before reading the current value + auto accessor = cache_.accessAllThreads(); IntT ret = readFastAndReset(); - for (auto& cache : cache_.accessAllThreads()) { + for (auto& cache : accessor) { if (!cache.reset_.load(std::memory_order_acquire)) { ret += cache.val_.load(std::memory_order_relaxed); cache.reset_.store(true, std::memory_order_release); @@ -114,19 +122,11 @@ class ThreadCachedInt : boost::noncopyable { target_.store(newVal, std::memory_order_release); } - // This is a little tricky - it's possible that our IntCaches are still alive - // in another thread and will get destroyed after this destructor runs, so we - // need to make sure we signal that this parent is dead. - ~ThreadCachedInt() { - for (auto& cache : cache_.accessAllThreads()) { - cache.parent_ = NULL; - } - } - private: std::atomic target_; std::atomic cacheSize_; - ThreadLocalPtr cache_; // Must be last for dtor ordering + ThreadLocalPtr + cache_; // Must be last for dtor ordering // This should only ever be modified by one thread struct IntCache { @@ -164,13 +164,9 @@ class ThreadCachedInt : boost::noncopyable { } ~IntCache() { - if (parent_) { - flush(); - } + flush(); } }; }; } - -#endif