1 /* 2 * Copyright (C) 2015 Nicolas Bonnefon and other contributors 3 * 4 * This file is part of glogg. 5 * 6 * glogg is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * glogg is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with glogg. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #ifndef THREADPRIVATESTORE_H 21 #define THREADPRIVATESTORE_H 22 23 #include <atomic> 24 #include <thread> 25 #include <cassert> 26 27 #include "log.h" 28 29 // This template stores data that is private to the calling thread 30 // in a completely wait-free manner. 31 template <typename T, int MAX_THREADS> 32 class ThreadPrivateStore 33 { 34 public: 35 // Construct an empty ThreadPrivateStore ThreadPrivateStore()36 ThreadPrivateStore() : nb_threads_( 0 ) { 37 // Last one is a guard 38 for ( int i=0; i<(MAX_THREADS+1); ++i ) 39 thread_ids_[i] = 0; 40 } 41 42 // Conversion to a T T()43 operator T() const 44 { return get(); } 45 46 // Getter (thread-safe, wait-free) get()47 T get() const 48 { return data_[threadIndex()]; } 49 getPtr()50 T* getPtr() 51 { return &data_[threadIndex()]; } 52 53 // Setter (thread-safe, wait-free) set(const T & value)54 void set( const T& value ) 55 { data_[threadIndex()] = value; } 56 57 private: 58 // Nb of threads that have registered 59 int nb_threads_; 60 61 // The actual data array (one element per thread from 0 to nb_threads_) 62 T data_[MAX_THREADS]; 63 64 mutable std::atomic<size_t> thread_ids_[MAX_THREADS+1]; 65 threadIndex()66 int threadIndex() const { 67 int i; 68 for ( i=0; thread_ids_[i]; ++i ) { 69 if ( thread_ids_[i].load() == 70 std::hash<std::thread::id>()(std::this_thread::get_id() ) ) { return i; } 71 } 72 73 // Current thread is missing, let's add it 74 size_t thread_id = std::hash<std::thread::id>()( std::this_thread::get_id() ); 75 while ( i < MAX_THREADS ) { 76 size_t expected = 0; 77 if ( thread_ids_[i++].compare_exchange_weak( expected, thread_id ) ) { 78 LOG(logDEBUG) << "Created thread for " << thread_id << " at index " << i-1; 79 return i-1; 80 } 81 } 82 83 assert( 1 ); 84 return 0; 85 } 86 }; 87 88 #endif 89