24 #include <sys/types.h> 30 #include <condition_variable> 36 #include <unordered_map> 38 #include <glog/logging.h> 48 using namespace folly;
73 auto const numElements = TLMeta::instance().elementsCapacity() + 1;
74 std::vector<ThreadLocal<size_t>> elems(numElements);
75 for (
auto&
t : elems) {
85 w.
reset(
new Widget());
110 auto deleter = [](Widget*
ptr) {
113 std::unique_ptr<Widget, decltype(deleter)> source(
new Widget(), deleter);
114 std::thread([&w, &source]() {
128 auto source = std::make_unique<Widget>();
129 std::thread([&w, &source]() {
142 tl.
reset(
new int(4));
152 std::unique_ptr<Widget> wPtr;
153 std::thread([&w, &wPtr]() {
154 w.
reset(
new Widget());
188 std::condition_variable cv;
197 t = std::thread([&]() {
203 std::unique_lock<std::mutex>
lock(mutex);
210 std::unique_lock<std::mutex>
lock(mutex);
211 while (state != State::EXIT) {
219 std::unique_lock<std::mutex>
lock(mutex);
220 while (state != State::DONE) {
235 std::unique_lock<std::mutex>
lock(mutex);
247 std::thread([&w]() { w->val_ += 10; }).
join();
254 std::thread([&w]() { w->
val_ += 10; }).
join();
272 std::unique_ptr<ThreadLocal<Widget>> w;
274 const int wVersionMax = 2;
277 auto th = std::thread([&]() {
278 int wVersionPrev = 0;
281 std::lock_guard<std::mutex>
g(lock);
282 if (wVersion > wVersionMax) {
285 if (wVersion > wVersionPrev) {
291 std::lock_guard<std::mutex>
g(lock);
292 wVersionPrev = wVersion;
300 std::lock_guard<std::mutex>
g(lock);
302 w = std::make_unique<ThreadLocal<Widget>>();
306 std::lock_guard<std::mutex>
g(lock);
307 if (thIter > thIterPrev) {
313 std::lock_guard<std::mutex>
g(lock);
314 wVersion = wVersionMax + 1;
341 std::atomic<bool>
run(
true);
342 std::atomic<int> totalAtomic{0};
343 std::vector<std::thread>
threads;
347 threads.push_back(std::thread([
i,
351 for (
int j = 0; j <=
i; j++) {
355 totalAtomic.fetch_add(1);
368 for (
auto&
t : threads) {
375 tl.
reset(
new int(4));
379 tl.
reset(
new int(5));
402 std::map<int, Foo>
map;
410 for (
auto&
m : map) {
411 tls.insert(
m.second.tl.get());
419 class ThreadCachedIntWidget {
421 ThreadCachedIntWidget() {}
423 ~ThreadCachedIntWidget() {
429 void set(detail::ThreadCachedInts<void>* ints) {
434 detail::ThreadCachedInts<void>* ints_{
nullptr};
439 detail::ThreadCachedInts<void> ints;
453 constexpr
size_t kFillObjectSize = 300;
455 std::atomic<uint64_t> gDestroyed;
465 explicit FillObject(
uint64_t idx) : idx_(idx) {
467 for (
size_t i = 0;
i < kFillObjectSize; ++
i) {
474 for (
size_t i = 0;
i < kFillObjectSize; ++
i) {
495 static constexpr
size_t numFillObjects = 250;
496 std::array<ThreadLocalPtr<FillObject>, numFillObjects> objects;
498 static constexpr
size_t numThreads = 32;
499 static constexpr
size_t numReps = 20;
501 std::vector<std::thread>
threads;
502 threads.reserve(numThreads);
504 for (
size_t k = 0;
k < numThreads; ++
k) {
505 threads.emplace_back([&objects] {
506 for (
size_t rep = 0; rep < numReps; ++rep) {
507 for (
size_t i = 0;
i < objects.size(); ++
i) {
508 objects[
i].reset(
new FillObject(rep * objects.size() +
i));
509 std::this_thread::sleep_for(std::chrono::microseconds(100));
511 for (
size_t i = 0;
i < objects.size(); ++
i) {
518 for (
auto&
t : threads) {
522 EXPECT_EQ(numFillObjects * numThreads * numReps, gDestroyed);
531 HoldsOne() : value_(1) {}
541 struct HoldsOneTag {};
555 #ifdef FOLLY_HAVE_PTHREAD_ATFORK 562 bool started =
false;
563 std::condition_variable startedCond;
564 bool stopped =
false;
565 std::condition_variable stoppedCond;
567 std::thread
t([&]() {
570 std::unique_lock<std::mutex>
lock(mutex);
572 startedCond.notify_all();
575 std::unique_lock<std::mutex>
lock(mutex);
577 stoppedCond.wait(lock);
583 std::unique_lock<std::mutex>
lock(mutex);
585 startedCond.wait(lock);
594 int v = totalValue();
605 }
else if (pid > 0) {
608 EXPECT_EQ(pid, waitpid(pid, &status, 0));
618 std::unique_lock<std::mutex>
lock(mutex);
620 stoppedCond.notify_all();
639 std::thread
t([&p] { p.
get(); });
649 }
else if (pid > 0) {
651 EXPECT_EQ(pid, waitpid(pid, &status, 0));
665 #if defined FOLLY_SANITIZE_ADDRESS || defined FOLLY_SANITIZE_THREAD || \ 666 !defined FOLLY_SUPPORT_SHARED_LIBRARY 667 #define SHARED_LIBRARY_TEST_NAME DISABLED_SharedLibrary 669 #define SHARED_LIBRARY_TEST_NAME SharedLibrary 674 auto lib =
exe.parent_path() /
"thread_local_test_lib.so";
675 auto handle = dlopen(
lib.string().c_str(), RTLD_LAZY);
677 <<
"unable to load " <<
lib.string() <<
": " << dlerror();
679 typedef void (*useA_t)();
681 useA_t
useA = (useA_t)dlsym(handle,
"useA");
683 const char* dlsym_error = dlerror();
691 std::thread t1([&]() {
697 std::thread t2([&]() {
718 namespace threadlocal_detail {
void reset(T *newPtr=nullptr)
void reset(T *newPtr=nullptr)
#define EXPECT_EQ(val1, val2)
Accessor accessAllThreads() const
constexpr detail::Map< Move > move
static size_t const kNumThreads
—— Concurrent Priority Queue Implementation ——
folly::Optional< PskKeyExchangeMode > mode
std::vector< std::thread::id > threads
#define FOR_EACH_RANGE(i, begin, end)
FOLLY_ALWAYS_INLINE void wait(const WaitOptions &opt=wait_options()) noexcept
FOLLY_ALWAYS_INLINE FOLLY_ATTR_VISIBILITY_HIDDEN T * get() const
State
See Core for details.
static void run(EventBaseManager *ebm, EventBase *eb, folly::Baton<> *stop, const StringPiece &name)
size_t read(T &out, folly::io::Cursor &cursor)
auto lock(Synchronized< D, M > &synchronized, Args &&...args)
static map< string, int > m
ThreadLocal< int, NewTag > val_
#define EXPECT_TRUE(condition)
uint64_t getCurrentThreadID()
uint64_t value(const typename LockFreeRingBuffer< T, Atom >::Cursor &rbcursor)
void join(const Delim &delimiter, Iterator begin, Iterator end, String &output)
#define ASSERT_NE(val1, val2)
#define EXPECT_FALSE(condition)
TEST(SequencedExecutor, CPUThreadPoolExecutor)
#define SHARED_LIBRARY_TEST_NAME
bool check(const dynamic &schema, const dynamic &value, bool check=true)