/* * Copyright (C) 2015 Nicolas Bonnefon and other contributors * * This file is part of glogg. * * glogg is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glogg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glogg. If not, see . */ #ifndef THREADPRIVATESTORE_H #define THREADPRIVATESTORE_H #include #include #include #include "log.h" // This template stores data that is private to the calling thread // in a completely wait-free manner. template class ThreadPrivateStore { public: // Construct an empty ThreadPrivateStore ThreadPrivateStore() : nb_threads_( 0 ) { // Last one is a guard for ( int i=0; i<(MAX_THREADS+1); ++i ) thread_ids_[i] = 0; } // Conversion to a T operator T() const { return get(); } // Getter (thread-safe, wait-free) T get() const { return data_[threadIndex()]; } T* getPtr() { return &data_[threadIndex()]; } // Setter (thread-safe, wait-free) void set( const T& value ) { data_[threadIndex()] = value; } private: // Nb of threads that have registered int nb_threads_; // The actual data array (one element per thread from 0 to nb_threads_) T data_[MAX_THREADS]; mutable std::atomic thread_ids_[MAX_THREADS+1]; int threadIndex() const { int i; for ( i=0; thread_ids_[i]; ++i ) { if ( thread_ids_[i].load() == std::hash()(std::this_thread::get_id() ) ) { return i; } } // Current thread is missing, let's add it size_t thread_id = std::hash()( std::this_thread::get_id() ); while ( i < MAX_THREADS ) { size_t expected = 0; if ( thread_ids_[i++].compare_exchange_weak( expected, thread_id ) ) { LOG(logDEBUG) << "Created thread for " << thread_id << " at index " << i-1; return i-1; } } assert( 1 ); return 0; } }; #endif