iLab Neuromorphic Robotics Toolkit  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ThreadHelpers.H
Go to the documentation of this file.
1 /*! @file
2  @author Shane Grant
3  @copyright GNU Public License (GPL v3)
4  @section License
5  @verbatim
6  // ////////////////////////////////////////////////////////////////////////
7  // The iLab Neuromorphic Robotics Toolkit (NRT) //
8  // Copyright 2010-2012 by the University of Southern California (USC) //
9  // and the iLab at USC. //
10  // //
11  // iLab - University of Southern California //
12  // Hedco Neurociences Building, Room HNB-10 //
13  // Los Angeles, Ca 90089-2520 - USA //
14  // //
15  // See http://ilab.usc.edu for information about this project. //
16  // ////////////////////////////////////////////////////////////////////////
17  // This file is part of The iLab Neuromorphic Robotics Toolkit. //
18  // //
19  // The iLab Neuromorphic Robotics Toolkit is free software: you can //
20  // redistribute it and/or modify it under the terms of the GNU General //
21  // Public License as published by the Free Software Foundation, either //
22  // version 3 of the License, or (at your option) any later version. //
23  // //
24  // The iLab Neuromorphic Robotics Toolkit is distributed in the hope //
25  // that it will be useful, but WITHOUT ANY WARRANTY; without even the //
26  // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //
27  // PURPOSE. See the GNU General Public License for more details. //
28  // //
29  // You should have received a copy of the GNU General Public License //
30  // along with The iLab Neuromorphic Robotics Toolkit. If not, see //
31  // <http://www.gnu.org/licenses/>. //
32  // ////////////////////////////////////////////////////////////////////////
33  @endverbatim */
34 
35 #ifndef INCLUDE_NRT_CORE_DESIGN_DETAILS_THREADHELPERS_H_
36 #define INCLUDE_NRT_CORE_DESIGN_DETAILS_THREADHELPERS_H_
37 
38 #include <mutex>
39 #include <memory>
40 #include <queue>
41 #include <thread>
42 
43 namespace nrt
44 {
45  //! Wraps up an std::function in a move copyable struct
47  {
48  private:
49  struct ImplBase
50  {
51  virtual void call() = 0;
52  virtual ~ImplBase()
53  { }
54  };
55 
56  std::unique_ptr<ImplBase> itsImpl;
57 
58  template <class Func>
59  struct ImplType : ImplBase
60  {
61  Func f;
62 
63  ImplType( Func && f_ ) : f( std::move( f_ ) )
64  { }
65 
66  void call()
67  {
68  f();
69  }
70  };
71 
72  public:
73  FunctionWrapper() = default;
74 
75  template<class Func>
76  FunctionWrapper( Func && f ) : itsImpl( new ImplType<Func>( std::move( f ) ) )
77  { }
78 
79  FunctionWrapper( FunctionWrapper && other ) : itsImpl( std::move( other.itsImpl ) )
80  { }
81 
82  FunctionWrapper( FunctionWrapper const & other ) = delete;
83  FunctionWrapper & operator=( FunctionWrapper const & other ) = delete;
84 
85  FunctionWrapper & operator=( FunctionWrapper && other )
86  {
87  itsImpl = std::move( other.itsImpl );
88  return *this;
89  }
90 
91  //! Calls the wrapped function
92  /*! \bug this used to segfault at the end of a program. Adding the test for itsImpl fixes it but wastes CPU */
93  void operator()()
94  {
95  if (itsImpl) itsImpl->call();
96  }
97  };
98 
99  //! Convenience RAII wrapper around a container of threads to call join() on all of them
100  template <template<typename, typename...> class Container, class ... Args>
102  {
103  ThreadJoiner( Container<std::thread, Args...> & threads ) : itsThreads( threads )
104  { }
105 
106  ~ThreadJoiner()
107  {
108  for( auto & t : itsThreads )
109  {
110  if( t.joinable() )
111  t.join();
112  }
113  }
114 
115  Container<std::thread, Args...> & itsThreads;
116  };
117 
118  //! A light wrapper around std::deque used to allow different threads to "steal" work
119  /*! Based off of an implementation in C++ Concurrency in Action: Practical Multithreading
120  by Anthony Williams */
122  {
123  private:
124  std::deque<FunctionWrapper> itsQueue;
125  mutable std::mutex itsMutex;
126 
127  public:
128  //! Create an empty queue
130  { }
131 
132  WorkStealingQueue( WorkStealingQueue const & other ) = delete;
133  WorkStealingQueue & operator=( WorkStealingQueue const & other ) = delete;
134 
135  //! Push a function onto the queue
136  void push( FunctionWrapper func )
137  {
138  std::lock_guard<std::mutex> lock( itsMutex );
139  itsQueue.push_front( std::move( func ) );
140  }
141 
142  //! Is the queue empty?
143  bool empty() const
144  {
145  std::lock_guard<std::mutex> lock( itsMutex );
146  return itsQueue.empty();
147  }
148 
149  //! Try to pop a function from the beginning of the queue
150  bool tryPop( FunctionWrapper & func )
151  {
152  std::lock_guard<std::mutex> lock( itsMutex );
153  if( itsQueue.empty() )
154  return false;
155 
156  func = std::move( itsQueue.front() );
157  itsQueue.pop_front();
158 
159  return true;
160  }
161 
162  //! Try to "steal" a function from the end of the queue
163  bool trySteal( FunctionWrapper & func )
164  {
165  std::lock_guard<std::mutex> lock( itsMutex );
166  if( itsQueue.empty() )
167  return false;
168 
169  func = std::move( itsQueue.back() );
170  itsQueue.pop_back();
171 
172  return true;
173  }
174  };
175 } // namespace nrt
176 
177 #endif // INCLUDE_NRT_CORE_DESIGN_DETAILS_THREADHELPERS_H_