#ifndef BOOST_THREAD_MEMBER_HPP #define BOOST_THREAD_MEMBER_HPP ////////////////////////////////////////////////////////////////////////////// // // (C) Copyright Vicente J. Botet Escriba 2008. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // Based on the threadalert library of Roland Schwarz // // I have added a cleanup functions and added the release function // the design is now more decoupled, separating the thread preamble // initialization and the thread_member_ptr type. // We don't need any more a new class thread that inherits from boost::thread, // we don't need neither the common context for the thread to manage the detach // the pointer from the map (this is done using the thread_specific_ptr cleanup). // Preambles will be called on the threads initialized using the // thread_preamble::proxy. // ////////////////////////////////////////////////////////////////////////////// // // The intent of this class is to allow two threads to establish a shared // memory space, without requiring the user code to pass any information. // This basically does work like a thread local storage from inside the // thread: // // boost::thread_member_ptr pmyclass; // // All functions known from thread_specific_ptr are available, and so is // semantics from inside the thread. // Besides this another thread can get access to the data by: // // pmyclass[th->get_id()]->foo(); // where "th" is a boost::thread* and "foo()" is a function of "myclass". // // The lifetime of the myclass instance is managed by a shared_ptr. // One reference is held by the thread (by means of a tss), a second is // held by the boost::thread object that created the thread, and additional // references might be held by other threads that obtained it by // "*pmyclass[th]". // // Please have a look at the "shared" example program to find out more. // // The stored tss pointers contain a references to the thread_member_ptr // instance and a shared pointer to T. // This tss pointer is stored on the preamble of the thread. // There is a map from the thread::id to the shared pointer. // On the cleanup phase the reference to the thread_member_ptr is used to // detach the shared pointer from the map. // ////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #include namespace boost { template class thread_member_ptr { private: thread_member_ptr(thread_member_ptr&); thread_member_ptr& operator=(thread_member_ptr&); typedef thread_member_ptr this_type; typedef shared_ptr shared_ptr_type; struct tss_type { template tss_type(this_type& type, T* ptr, Deleter deleter) : type_(type) , shptr_(ptr, deleter) {} thread_member_ptr& type_; shared_ptr_type shptr_; }; typedef std::map map_type; typedef thread_specific_ptr tss_ptr_type; mutex monitor_; condition mapchanged_; void (*deleter_)(T*); tss_ptr_type tss_ptr_; map_type tmap_; static void detach_data(tss_type* ptr) { ptr->type_.detach_from_current_thread(); delete ptr; } static void delete_data(T* data) { delete data; } void detach_from_current_thread() { boost::mutex::scoped_lock lock(monitor_); tmap_.erase(boost::this_thread::get_id()); } public: thread_member_ptr() : deleter_(delete_data) , tss_ptr_(detach_data) {} explicit thread_member_ptr(void (*func_)(T*)) : deleter_(func_) , tss_ptr_(detach_data) {} ~thread_member_ptr() {} T* get() const { tss_type* tss_ptr=tss_ptr_.get(); if (tss_ptr==0) { return 0; } else return tss_ptr->shptr_.get(); } T* operator->() const { return get(); } T& operator*() const { return *get(); } shared_ptr_type release() { // get the tss tss_type* tss_ptr=tss_ptr_.get(); // copy the shared pointer shared_ptr_type temp= tss_ptr->shptr_; // release the ptr tss_ptr->shptr_.release(); { // erase from the map boost::mutex::scoped_lock lock(monitor_); tmap_.erase(boost::this_thread::get_id()); } // return the copied shared pointer return temp; } void reset(T* p=0) { // get the tss tss_type* tss_ptr=tss_ptr_.get(); if (tss_ptr==0) { tss_ptr = new tss_type(*this, p, deleter_); tss_ptr_.reset(tss_ptr); } else { // reset the shared pointer the existing tss_ptr->shptr_.reset(p); } { // update the map mutex::scoped_lock lock(monitor_); tmap_[boost::this_thread::get_id()] = tss_ptr->shptr_; // and notify the change mapchanged_.notify_all(); } } const shared_ptr_type operator[](boost::thread::id id) { mutex::scoped_lock lock(monitor_); typename map_type::const_iterator i(tmap_.find(id)); if ( i == tmap_.end()) { return shared_ptr_type(); } else { return i->second; } } const shared_ptr_type wait_and_get(boost::thread::id id) { typename map_type::const_iterator i; mutex::scoped_lock lock(monitor_); while ((i = tmap_.find(id)) == tmap_.end()) mapchanged_.wait(lock); return i->second; } }; } #include #endif