Simbody  3.4 (development)
ThreadLocal.h
Go to the documentation of this file.
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_
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines