| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| #ifndef KUDU_UTIL_THREADLOCAL_H_ |
| #define KUDU_UTIL_THREADLOCAL_H_ |
| |
| // Block-scoped static thread local implementation. |
| // |
| // Usage is similar to a C++11 thread_local. The BLOCK_STATIC_THREAD_LOCAL macro |
| // defines a thread-local pointer to the specified type, which is lazily |
| // instantiated by any thread entering the block for the first time. The |
| // constructor for the type T is invoked at macro execution time, as expected, |
| // and its destructor is invoked when the corresponding thread's Runnable |
| // returns, or when the thread exits. |
| // |
| // Inspired by Poco <http://pocoproject.org/docs/Poco.ThreadLocal.html>, |
| // Andrew Tomazos <http://stackoverflow.com/questions/12049684/>, and |
| // the C++11 thread_local API. |
| // |
| // Example usage: |
| // |
| // // Invokes a 3-arg constructor on SomeClass: |
| // BLOCK_STATIC_THREAD_LOCAL(SomeClass, instance, arg1, arg2, arg3); |
| // instance->DoSomething(); |
| // |
| #define BLOCK_STATIC_THREAD_LOCAL(T, t, ...) \ |
| static __thread T* t; \ |
| do { \ |
| if (PREDICT_FALSE(t == NULL)) { \ |
| t = new T(__VA_ARGS__); \ |
| threadlocal::internal::AddDestructor(threadlocal::internal::Destroy<T>, t); \ |
| } \ |
| } while (false) |
| |
| // Class-scoped static thread local implementation. |
| // |
| // Very similar in implementation to the above block-scoped version, but |
| // requires a bit more syntax and vigilance to use properly. |
| // |
| // DECLARE_STATIC_THREAD_LOCAL(Type, instance_var_) must be placed in the |
| // class header, as usual for variable declarations. |
| // |
| // Because these variables are static, they must also be defined in the impl |
| // file with DEFINE_STATIC_THREAD_LOCAL(Type, Classname, instance_var_), |
| // which is very much like defining any static member, i.e. int Foo::member_. |
| // |
| // Finally, each thread must initialize the instance before using it by calling |
| // INIT_STATIC_THREAD_LOCAL(Type, instance_var_, ...). This is a cheap |
| // call, and may be invoked at the top of any method which may reference a |
| // thread-local variable. |
| // |
| // Due to all of these requirements, you should probably declare TLS members |
| // as private. |
| // |
| // Example usage: |
| // |
| // // foo.h |
| // #include "kudu/utils/file.h" |
| // class Foo { |
| // public: |
| // void DoSomething(std::string s); |
| // private: |
| // DECLARE_STATIC_THREAD_LOCAL(utils::File, file_); |
| // }; |
| // |
| // // foo.cc |
| // #include "kudu/foo.h" |
| // DEFINE_STATIC_THREAD_LOCAL(utils::File, Foo, file_); |
| // void Foo::WriteToFile(std::string s) { |
| // // Call constructor if necessary. |
| // INIT_STATIC_THREAD_LOCAL(utils::File, file_, "/tmp/file_location.txt"); |
| // file_->Write(s); |
| // } |
| |
| // Goes in the class declaration (usually in a header file). |
| // dtor must be destructed _after_ t, so it gets defined first. |
| // Uses a mangled variable name for dtor since it must also be a member of the |
| // class. |
| #define DECLARE_STATIC_THREAD_LOCAL(T, t) \ |
| static __thread T* t |
| |
| // You must also define the instance in the .cc file. |
| #define DEFINE_STATIC_THREAD_LOCAL(T, Class, t) \ |
| __thread T* Class::t |
| |
| // Must be invoked at least once by each thread that will access t. |
| #define INIT_STATIC_THREAD_LOCAL(T, t, ...) \ |
| do { \ |
| if (PREDICT_FALSE(t == NULL)) { \ |
| t = new T(__VA_ARGS__); \ |
| threadlocal::internal::AddDestructor(threadlocal::internal::Destroy<T>, t); \ |
| } \ |
| } while (false) |
| |
| // Internal implementation below. |
| |
| namespace kudu { |
| namespace threadlocal { |
| namespace internal { |
| |
| // Add a destructor to the list. |
| void AddDestructor(void (*destructor)(void*), void* arg); |
| |
| // Destroy the passed object of type T. |
| template<class T> |
| static void Destroy(void* t) { |
| // With tcmalloc, this should be pretty cheap (same thread as new). |
| delete reinterpret_cast<T*>(t); |
| } |
| |
| } // namespace internal |
| } // namespace threadlocal |
| } // namespace kudu |
| |
| #endif // KUDU_UTIL_THREADLOCAL_H_ |