Lunchbox  1.13.0
Multi-threaded C++ toolbox library for all application developers creating high-performance multi-threaded programs.
thread.h
1 
2 /* Copyright (c) 2005-2014, Stefan Eilemann <eile@equalizergraphics.com>
3  * 2012, Marwan Abdellah <marwan.abdellah@epfl.ch>
4  * 2012, Daniel Nachbaur <danielnachbaur@gmail.com>
5  *
6  * This library is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU Lesser General Public License version 2.1 as published
8  * by the Free Software Foundation.
9  *
10  * This library is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12  * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
13  * details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this library; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 #ifndef LUNCHBOX_THREAD_H
21 #define LUNCHBOX_THREAD_H
22 
23 #include <lunchbox/api.h> // LUNCHBOX_API definition
24 #include <lunchbox/debug.h> // debug macros in thread-safety checks
25 #include <lunchbox/threadID.h> // member
26 #include <lunchbox/types.h>
27 
28 #include <boost/noncopyable.hpp>
29 #include <ostream>
30 
31 namespace lunchbox
32 {
33 namespace detail { class Thread; }
34 
41 class Thread
42 {
43 public:
45  enum Affinity
46  {
47  NONE = 0,
48  CORE = 1,
49  SOCKET = -65536,
50  SOCKET_MAX = -1024
51  };
52 
54  LUNCHBOX_API Thread();
55 
57  LUNCHBOX_API explicit Thread( const Thread& from );
58 
60  LUNCHBOX_API virtual ~Thread();
61 
70  LUNCHBOX_API virtual bool start();
71 
83  virtual bool init(){ return true; }
84 
93  virtual void run() = 0;
94 
103  LUNCHBOX_API virtual void exit();
104 
111  LUNCHBOX_API void cancel();
112 
119  LUNCHBOX_API bool join();
120 
130  LUNCHBOX_API bool isStopped() const;
131 
141  LUNCHBOX_API bool isRunning() const;
142 
148  LUNCHBOX_API bool isCurrent() const;
149 
151  LUNCHBOX_API static ThreadID getSelfThreadID();
152 
154  LUNCHBOX_API static void yield();
155 
157  LUNCHBOX_API static void setName( const std::string& name );
158 
169  LUNCHBOX_API static void setAffinity( const int32_t affinity );
170 
171 private:
172  detail::Thread* const _impl;
173 
174  Thread& operator=( const Thread& ) { return *this; }
175 
176  static void* runChild( void* arg );
177  void _runChild();
178 
179  friend void lunchbox::abort( bool );
180  static void _dumpAll();
181 };
182 
184 LUNCHBOX_API std::ostream& operator << ( std::ostream&, const Thread::Affinity );
185 
186 // These thread-safety checks are for development purposes, to check that
187 // certain objects are properly used within the framework. Leaving them enabled
188 // during application development may cause false positives, e.g., when
189 // threadsafety is ensured outside of the objects by the application.
190 
191 #ifndef NDEBUG
192 # define LB_CHECK_THREADSAFETY
193 #endif
194 
196 #define LB_TS_VAR( NAME ) \
197  public: \
198  struct NAME ## Struct \
199  { \
200  NAME ## Struct () \
201  : extMutex( false ) \
202  {} \
203  mutable lunchbox::ThreadID id; \
204  mutable std::string name; \
205  bool extMutex; \
206  mutable lunchbox::ThreadID inRegion; \
207  } NAME; \
208 private:
209 
210 #ifdef LB_CHECK_THREADSAFETY
211 # define LB_TS_RESET( NAME ) NAME.id = lunchbox::ThreadID();
212 
213 # define LB_TS_THREAD( NAME ) \
214  { \
215  if( NAME.id == lunchbox::ThreadID( )) \
216  { \
217  NAME.id = lunchbox::Thread::getSelfThreadID(); \
218  NAME.name = lunchbox::Log::instance().getThreadName(); \
219  LBVERB << "Functions for " << #NAME \
220  << " locked from" << lunchbox::backtrace << std::endl; \
221  } \
222  if( !NAME.extMutex && NAME.id != lunchbox::Thread::getSelfThreadID( )) \
223  { \
224  LBERROR << "Threadsafety check for " << #NAME \
225  << " failed on object of type " \
226  << lunchbox::className( this ) << ", thread " \
227  << lunchbox::Thread::getSelfThreadID() << " (" \
228  << lunchbox::Log::instance().getThreadName() << ") != " \
229  << NAME.id << " (" << NAME.name << ")" << std::endl; \
230  LBABORT( "Non-threadsafe code called from two threads" ); \
231  } \
232  }
233 
234 # define LB_TS_NOT_THREAD( NAME ) \
235  { \
236  if( !NAME.extMutex && NAME.id != lunchbox::ThreadID( )) \
237  { \
238  if( NAME.id == lunchbox::Thread::getSelfThreadID( )) \
239  { \
240  LBERROR << "Threadsafety check for not " << #NAME \
241  << " failed on object of type " \
242  << lunchbox::className( this ) << std::endl; \
243  LBABORT( "Code called from wrong thread" ); \
244  } \
245  } \
246  }
247 
249 template< typename T > class ScopedThreadCheck : public boost::noncopyable
250 {
251 public:
252  explicit ScopedThreadCheck( const T& data )
253  : _data( data )
254  {
255  LBASSERTINFO( data.inRegion == lunchbox::ThreadID() ||
256  data.inRegion == lunchbox::Thread::getSelfThreadID(),
257  "Another thread already in critical region" );
258  data.inRegion = lunchbox::Thread::getSelfThreadID();
259  }
260 
261  ~ScopedThreadCheck()
262  {
263  LBASSERTINFO( _data.inRegion == lunchbox::ThreadID() ||
264  _data.inRegion == lunchbox::Thread::getSelfThreadID(),
265  "Another thread entered critical region" );
266  _data.inRegion = lunchbox::ThreadID();
267  }
268 private:
269  const T& _data;
270 };
273 # define LB_TS_SCOPED( NAME ) \
274  lunchbox::ScopedThreadCheck< NAME ## Struct > scoped ## NAME ## Check(NAME);
275 
276 #else
277 # define LB_TS_RESET( NAME ) {}
278 # define LB_TS_THREAD( NAME ) {}
279 # define LB_TS_NOT_THREAD( NAME ) {}
280 # define LB_TS_SCOPED( NAME ) {}
281 #endif
282 
283 }
284 #endif //LUNCHBOX_THREAD_H
static ThreadID getSelfThreadID()
Bind to a specific CPU core.
Definition: thread.h:48
Defines export visibility macros for library Lunchbox.
Basic type definitions not provided by the operating system.
Highest bindable CPU.
Definition: thread.h:50
Affinity
Enumeration values for thread affinity.
Definition: thread.h:45
Utility class to execute code in a separate execution thread.
Definition: thread.h:41
An utility class to wrap OS-specific thread identifiers.
Definition: threadID.h:32
bool isStopped() const
Return if the thread is stopped.
Don't set any affinity.
Definition: thread.h:47
virtual ~Thread()
Destruct the thread.
Bind to all cores of a specific socket (CPU)
Definition: thread.h:49
void cancel()
Cancel (stop) the child thread.
bool isCurrent() const
Abstraction layer and common utilities for multi-threaded programming.
Definition: algorithm.h:32
virtual bool start()
Start the thread.
std::ostream & operator<<(std::ostream &os, const Array< T > &array)
Pretty-print all members of the array.
Definition: array.h:47
bool isRunning() const
Return if the thread is running.
bool join()
Wait for the exit of the child thread.
virtual bool init()
The init function for the child thread.
Definition: thread.h:83
virtual void exit()
Exit the child thread immediately.
Thread()
Construct a new thread.
virtual void run()=0
The entry function for the child thread.