Rosetta
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
threadsafe_creation.hh
Go to the documentation of this file.
1 // -*- mode:c++;tab-width:2;indent-tabs-mode:t;show-trailing-whitespace:t;rm-trailing-spaces:t -*-
2 // vi: set ts=2 noet:
3 //
4 // (c) Copyright Rosetta Commons Member Institutions.
5 // (c) This file is part of the Rosetta software suite and is made available under license.
6 // (c) The Rosetta software is developed by the contributing members of the Rosetta Commons.
7 // (c) For more information, see http://www.rosettacommons.org. Questions about this can be
8 // (c) addressed to University of Washington UW TechTransfer, email: license@u.washington.edu.
9 
10 #ifndef INCLUDED_utility_thread_threadsafe_creation_HH
11 #define INCLUDED_utility_thread_threadsafe_creation_HH
12 
13 // Unit headers
15 
16 // Boost headers
17 #include <boost/function.hpp>
18 
19 #ifdef MULTI_THREADED
20 #ifdef CXX11
21 
23 #include <thread>
24 
25 #endif
26 #endif
27 
28 // Utility headers
30 
31 // C++ headers
32 #include <map>
33 
34 namespace utility {
35 namespace thread {
36 
37 /// @brief Safely instantiate a singleton class in a (possibly)
38 /// multithreaded context.
39 ///
40 /// @details In the non-multithreaded case, this simply checks the
41 /// singleton's instance member; in the multithreaded case, it
42 /// checks the instance member, then it obtains the singleton's
43 /// instance-creation mutex, then it checks the instance member
44 /// again, to ensure that no other thread has already created the
45 /// instance, it creates the instance, and then it releases the mutex.
46 ///
47 /// Requires that class T defines:
48 /// static std::mutex & singleton_mutex(),
49 template < class T >
50 void
52  boost::function< T * () > creation_func,
53 #if defined MULTI_THREADED && defined CXX11
54  std::atomic< T * > & instance
55 #else
56  T * & instance
57 #endif
58 ) {
59 
60 #ifdef MULTI_THREADED
61 #ifdef CXX11
62  // threadsafe version that uses c++11 interface
63  // taken from http://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/
64  T * local_instance = instance.load( std::memory_order_relaxed );
65  std::atomic_thread_fence( std::memory_order_acquire );
66  if ( ! local_instance ) {
67  std::lock_guard< std::mutex > lock( T::singleton_mutex() );
68  local_instance = instance.load( std::memory_order_relaxed );
69  if ( ! instance ) {
70  local_instance = creation_func();
71  instance.store( local_instance, std::memory_order_relaxed );
72  std::atomic_thread_fence( std::memory_order_release );
73  }
74  }
75 #else
76  // ok, multithreaded w/o cxx11
77  // not actually threadsafe!
78  // http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
79  if ( ! instance ) {
80  instance = creation_func();
81  }
82 #endif
83 #else
84  // not multithreaded; standard singleton instantiation logic
85  if ( ! instance ) {
86  instance = creation_func();
87  }
88 #endif
89 
90 }
91 
92 
93 #ifdef MULTI_THREADED
94 #ifdef CXX11
95 
96 /// @brief Safely create and insert an object into a map that is guarded by
97 /// a utility::thread::ReadWriteMutex. Uses boost::function to invoke
98 /// the creation function only if needed (i.e. it will not invoke the creation
99 /// function if the item has already been created by the time the WriteLockGuard
100 /// has been acquired.
101 ///
102 /// @details First create a WriteLockGuard for the input ReadWriteMutext, blocking
103 /// until all other threads stop reading from or writing to the tmap. Then search
104 /// the tmap to make sure that object being created (and identified by "tname") has
105 /// not already been inserted into the map (after all, another thread may have called
106 /// this very function before this thread did, and may have already created the
107 /// desired object). If the object is still not in the tmap, then it is safe to
108 /// create the object and to insert it into the map.
109 ///
110 /// This function returns an iterator for the newly-inserted map element.
111 template < class T >
112 typename std::map< std::string, utility::pointer::shared_ptr< T > >::const_iterator
113 create_and_insert(
114  typename boost::function< utility::pointer::shared_ptr< T > () > builder,
115  utility::thread::ReadWriteMutex & wrm,
116  std::string const & tname,
117  typename std::map< std::string, utility::pointer::shared_ptr< T > > & tmap
118 )
119 {
120  utility::thread::WriteLockGuard lock( wrm );
121  typename std::map< std::string, utility::pointer::shared_ptr< T > >::const_iterator iter;
122 
123  iter = tmap.find( tname );
124  if ( iter == tmap.end() ) {
125  utility::pointer::shared_ptr< T > newT = builder();
126  iter = tmap.insert( std::make_pair( tname, newT )).first;
127  }
128  return iter;
129 }
130 
131 #endif
132 #endif
133 
134 
135 }
136 }
137 
138 #endif
utility::keys::KeyLookup< KeyType >::const_iterator const_iterator
Key collection iterators.
Non-owning access smart pointer – dispatch class.
Classes to manage data that can be read by multiple threads and written to by only one thread...
void safely_create_singleton(T *&instance)