Simbody
3.4 (development)
|
00001 #ifndef SimTK_SimTKCOMMON_THREAD_LOCAL_H_ 00002 #define SimTK_SimTKCOMMON_THREAD_LOCAL_H_ 00003 00004 /* -------------------------------------------------------------------------- * 00005 * Simbody(tm): SimTKcommon * 00006 * -------------------------------------------------------------------------- * 00007 * This is part of the SimTK biosimulation toolkit originating from * 00008 * Simbios, the NIH National Center for Physics-Based Simulation of * 00009 * Biological Structures at Stanford, funded under the NIH Roadmap for * 00010 * Medical Research, grant U54 GM072970. See https://simtk.org/home/simbody. * 00011 * * 00012 * Portions copyright (c) 2008-12 Stanford University and the Authors. * 00013 * Authors: Peter Eastman * 00014 * Contributors: * 00015 * * 00016 * Licensed under the Apache License, Version 2.0 (the "License"); you may * 00017 * not use this file except in compliance with the License. You may obtain a * 00018 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0. * 00019 * * 00020 * Unless required by applicable law or agreed to in writing, software * 00021 * distributed under the License is distributed on an "AS IS" BASIS, * 00022 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 00023 * See the License for the specific language governing permissions and * 00024 * limitations under the License. * 00025 * -------------------------------------------------------------------------- */ 00026 00027 #include <pthread.h> 00028 #include <map> 00029 #include <set> 00030 00031 namespace SimTK { 00032 00033 static std::map<void*, pthread_key_t> instanceMap; 00034 static std::map<pthread_key_t, std::set<void*> > keyInstances; 00035 static pthread_mutex_t keyLock = PTHREAD_MUTEX_INITIALIZER; 00036 00037 template <class T> 00038 static void cleanUpThreadLocalStorage(void* value) { 00039 00040 // Delete the value. 00041 00042 T* t = reinterpret_cast<T*>(value); 00043 delete t; 00044 00045 // Remove it from the set of values needing to be deleted. 00046 00047 pthread_mutex_lock(&keyLock); 00048 pthread_key_t key = instanceMap[value]; 00049 instanceMap.erase(value); 00050 if (keyInstances.find(key) != keyInstances.end()) 00051 keyInstances.find(key)->second.erase(value); 00052 pthread_mutex_unlock(&keyLock); 00053 00054 } 00055 00075 template <class T> 00076 class ThreadLocal { 00077 public: 00081 ThreadLocal() { 00082 this->initialize(); 00083 } 00089 ThreadLocal(const T& defaultValue) : defaultValue(defaultValue) { 00090 this->initialize(); 00091 } 00092 ~ThreadLocal() { 00093 00094 // Delete the key. 00095 00096 pthread_key_delete(key); 00097 00098 // Once the key is deleted, cleanUpThreadLocalStorage() will no longer be called, so delete 00099 // all instances now. 00100 00101 pthread_mutex_lock(&keyLock); 00102 std::set<void*>& instances = keyInstances[key]; 00103 for (std::set<void*>::const_iterator iter = instances.begin(); iter != instances.end(); ++iter) { 00104 instanceMap.erase(*iter); 00105 delete (T*) *iter; 00106 } 00107 keyInstances.erase(key); 00108 pthread_mutex_unlock(&keyLock); 00109 } 00113 T& upd() { 00114 T* value = reinterpret_cast<T*>(pthread_getspecific(key)); 00115 if (value == NULL) 00116 return createValue(); 00117 return *value; 00118 } 00122 const T& get() const { 00123 T* value = reinterpret_cast<T*>(pthread_getspecific(key)); 00124 if (value == NULL) 00125 return createValue(); 00126 return *value; 00127 } 00128 private: 00129 void initialize() { 00130 pthread_key_create(&key, cleanUpThreadLocalStorage<T>); 00131 pthread_mutex_lock(&keyLock); 00132 keyInstances[key] = std::set<void*>(); 00133 pthread_mutex_unlock(&keyLock); 00134 } 00135 T& createValue() const { 00136 T* value = new T(defaultValue); 00137 pthread_setspecific(key, value); 00138 pthread_mutex_lock(&keyLock); 00139 instanceMap[value] = key; 00140 keyInstances[key].insert(value); 00141 pthread_mutex_unlock(&keyLock); 00142 return *value; 00143 } 00144 pthread_key_t key; 00145 T defaultValue; 00146 }; 00147 00148 } // namespace SimTK 00149 00150 #endif // SimTK_SimTKCOMMON_THREAD_LOCAL_H_