ARC SDK
Thread.h
1 // -*- indent-tabs-mode: nil -*-
2 
3 #ifndef __ARC_THREAD_H__
4 #define __ARC_THREAD_H__
5 
6 #include <map>
7 
8 #include <glibmm/thread.h>
9 
10 namespace Arc {
11 
15  class SimpleCondition;
16  class SimpleCounter;
17 
18  // This module provides convenient helpers for Glibmm interface for thread
19  // management. So far it takes care of automatic initialization
20  // of threading environment and creation of simple detached threads.
21  // Always use it instead of glibmm/thread.h and keep among first
22  // includes. It safe to use it multiple times and to include it both
23  // from source files and other include files.
24 
29  const size_t thread_stacksize = (16 * 1024 * 1024);
32 
33 
38  bool CreateThreadFunction(void (*func)(void*), void *arg, SimpleCounter* count = NULL);
39 
40  class ThreadData;
41 
43 
48  friend class ThreadData;
49  private:
50  ThreadDataItem(const ThreadDataItem& it);
51  protected:
52  virtual ~ThreadDataItem(void);
53  public:
55 
56  ThreadDataItem(void);
58 
60  ThreadDataItem(std::string& key);
62  ThreadDataItem(const std::string& key);
64 
67  void Attach(std::string& key);
69 
71  void Attach(const std::string& key);
73 
74  static ThreadDataItem* Get(const std::string& key);
76 
80  virtual void Dup(void);
81  };
82 
84 
87  private:
88  Glib::Cond cond_;
89  Glib::Mutex lock_;
90  unsigned int flag_;
91  unsigned int waiting_;
92  public:
93  SimpleCondition(void)
94  : flag_(0), waiting_(0) {}
95  ~SimpleCondition(void) {
96  /* race condition ? */
97  broadcast();
98  }
100  void lock(void) {
101  lock_.lock();
102  }
104  void unlock(void) {
105  lock_.unlock();
106  }
108  void signal(void) {
109  lock_.lock();
110  flag_ = 1;
111  cond_.signal();
112  lock_.unlock();
113  }
115 
116  void signal_nonblock(void) {
117  flag_ = 1;
118  cond_.signal();
119  }
121 
122  void broadcast(void) {
123  lock_.lock();
124  flag_ = waiting_?waiting_:1;
125  cond_.broadcast();
126  lock_.unlock();
127  }
129  void wait(void) {
130  lock_.lock();
131  ++waiting_;
132  while (!flag_) cond_.wait(lock_);
133  --waiting_;
134  --flag_;
135  lock_.unlock();
136  }
138 
139  void wait_nonblock(void) {
140  ++waiting_;
141  while (!flag_) cond_.wait(lock_);
142  --waiting_;
143  --flag_;
144  }
146 
147  bool wait(int t) {
148  lock_.lock();
149  Glib::TimeVal etime;
150  etime.assign_current_time();
151  etime.add_milliseconds(t);
152  bool res(true);
153  ++waiting_;
154  while (!flag_) {
155  res = cond_.timed_wait(lock_, etime);
156  if (!res) break;
157  }
158  --waiting_;
159  if(res) --flag_;
160  lock_.unlock();
161  return res;
162  }
164  void reset(void) {
165  lock_.lock();
166  flag_ = 0;
167  lock_.unlock();
168  }
170 
171  void forceReset(void) {
172  flag_ = 0;
173  waiting_ = 0;
174  lock_.unlock();
175  }
176  };
177 
179 
182  private:
183  Glib::Cond cond_;
184  Glib::Mutex lock_;
185  int count_;
186  public:
187  SimpleCounter(void) : count_(0) {}
188  virtual ~SimpleCounter(void);
190 
191  virtual int inc(void);
193 
194  virtual int dec(void);
196  virtual int get(void) const;
198 
199  virtual int set(int v);
201  virtual void wait(void) const;
203 
205  virtual bool wait(int t) const;
207 
208  virtual void forceReset(void) {
209  lock_.unlock();
210  }
211  };
212 
214 
215  class TimedMutex {
216  private:
217  Glib::Cond cond_;
218  Glib::Mutex lock_;
219  bool locked_;
220  public:
221  TimedMutex(void):locked_(false) { };
222  ~TimedMutex(void) { };
224 
225  bool lock(int t = -1) {
226  lock_.lock();
227  if(t < 0) { // infinite
228  while(locked_) {
229  cond_.wait(lock_);
230  };
231  } else if(t > 0) { // timed
232  Glib::TimeVal etime;
233  etime.assign_current_time();
234  etime.add_milliseconds(t);
235  while(locked_) {
236  if(!cond_.timed_wait(lock_, etime)) break;
237  };
238  };
239  bool res = !locked_;
240  locked_=true;
241  lock_.unlock();
242  return res;
243  };
245  bool trylock(void) {
246  return lock(0);
247  };
249  bool unlock(void) {
250  lock_.lock();
251  bool res = locked_;
252  if(res) {
253  locked_ = false;
254  cond_.signal();
255  };
256  lock_.unlock();
257  return true;
258  };
260 
261  void forceReset(void) {
262  locked_ = false;
263  lock_.unlock();
264  }
265  };
266 
268 
269  class SharedMutex {
270  private:
271  Glib::Cond cond_;
272  Glib::Mutex lock_;
273  unsigned int exclusive_;
274  Glib::Thread* thread_;
275  typedef std::map<Glib::Thread*,unsigned int> shared_list;
276  shared_list shared_;
277  void add_shared_lock(void);
278  void remove_shared_lock(void);
279  bool have_shared_lock(void);
280  inline bool have_exclusive_lock(void) {
281  if(!exclusive_) return false;
282  if(thread_ == Glib::Thread::self()) return false;
283  return true;
284  };
285  public:
286  SharedMutex(void):exclusive_(0),thread_(NULL) { };
287  ~SharedMutex(void) { };
289  void lockShared(void);
291  void unlockShared(void);
293  bool isLockShared(void) {
294  return (shared_.size() > 0); // Is it safe?
295  };
297  void lockExclusive(void);
299  void unlockExclusive(void);
301  bool isLockExclusive(void) {
302  return (exclusive_ > 0);
303  };
305 
306  void forceReset(void) {
307  exclusive_ = 0;
308  thread_ = NULL;
309  shared_.clear();
310  lock_.unlock();
311  };
312  };
313 
316  class ThreadedPointerBase {
317  private:
318  Glib::Mutex lock_;
319  Glib::Cond cond_;
320  unsigned int cnt_;
321  void *ptr_;
322  bool released_;
323  ThreadedPointerBase(ThreadedPointerBase&);
324  ~ThreadedPointerBase(void);
325  public:
326  ThreadedPointerBase(void *p);
327  ThreadedPointerBase* add(void);
328  void* rem(void);
329  void* ptr(void) const { return ptr_; };
330  void rel(void) { released_ = true; };
331  unsigned int cnt(void) const { return cnt_; };
332  void lock(void) { lock_.lock(); };
333  void unlock(void) { lock_.unlock(); };
334  void wait(void) { cond_.wait(lock_); };
335  bool wait(Glib::TimeVal etime) {
336  return cond_.timed_wait(lock_,etime);
337  };
338  };
341 
342 
347  template<typename T>
349  private:
350  ThreadedPointerBase *object_;
351  public:
352  ThreadedPointer(T *p)
353  : object_(new ThreadedPointerBase(p)) {}
355  : object_(p.object_->add()) {}
356  ThreadedPointer(void)
357  : object_(new ThreadedPointerBase(NULL)) {}
358  ~ThreadedPointer(void) {
359  delete((T*)(object_->rem()));
360  }
361  ThreadedPointer<T>& operator=(T *p) {
362  if (p != object_->ptr()) {
363  delete((T*)(object_->rem()));
364  object_ = new ThreadedPointerBase(p);
365  }
366  return *this;
367  }
368  ThreadedPointer<T>& operator=(const ThreadedPointer<T>& p) {
369  if (p.object_->ptr() != object_->ptr()) {
370  delete((T*)(object_->rem()));
371  object_ = p.object_->add();
372  }
373  return *this;
374  }
376  T& operator*(void) const {
377  return *(T*)(object_->ptr());
378  }
380  T* operator->(void) const {
381  return (T*)(object_->ptr());
382  }
384  operator bool(void) const {
385  return ((object_->ptr()) != NULL);
386  }
388  bool operator!(void) const {
389  return ((object_->ptr()) == NULL);
390  }
392  bool operator==(const ThreadedPointer& p) const {
393  return ((T*)(object_->ptr()) == (T*)(p.object_->ptr()));
394  }
396  bool operator!=(const ThreadedPointer& p) const {
397  return ((T*)(object_->ptr()) != (T*)(p.object_->ptr()));
398  }
400  bool operator<(const ThreadedPointer& p) const {
401  return ((T*)(object_->ptr()) < (T*)(p.object_->ptr()));
402  }
404  T* Ptr(void) const {
405  return (T*)(object_->ptr());
406  }
408 
410  T* Release(void) {
411  T* tmp = (T*)(object_->ptr());
412  object_->rel();
413  return tmp;
414  }
416  unsigned int Holders(void) {
417  return object_->cnt();
418  }
420  /* Returns current number of instances. */
421  unsigned int WaitOutRange(unsigned int minThr, unsigned int maxThr) {
422  unsigned int r = 0;
423  object_->lock();
424  for(;;) {
425  r = object_->cnt();
426  if(r <= minThr) break;
427  if(r >= maxThr) break;
428  object_->wait();
429  };
430  object_->unlock();
431  return r;
432  }
434 
436  unsigned int WaitOutRange(unsigned int minThr, unsigned int maxThr, int timeout) {
437  if(timeout < 0) return WaitOutRange(minThr, maxThr);
438  unsigned int r = 0;
439  object_->lock();
440  Glib::TimeVal etime;
441  etime.assign_current_time();
442  etime.add_milliseconds(timeout);
443  for(;;) {
444  r = object_->cnt();
445  if(r <= minThr) break;
446  if(r >= maxThr) break;
447  if(!object_->wait(etime)) break;
448  };
449  object_->unlock();
450  return r;
451  }
453  /* Returns current number of instances. */
454  unsigned int WaitInRange(unsigned int minThr, unsigned int maxThr) {
455  unsigned int r = 0;
456  object_->lock();
457  for(;;) {
458  r = object_->cnt();
459  if((r >= minThr) && (r <= maxThr)) break;
460  object_->wait();
461  };
462  object_->unlock();
463  return r;
464  }
466 
468  unsigned int WaitInRange(unsigned int minThr, unsigned int maxThr, int timeout) {
469  if(timeout < 0) return WaitInRange(minThr, maxThr);
470  unsigned int r = 0;
471  object_->lock();
472  Glib::TimeVal etime;
473  etime.assign_current_time();
474  etime.add_milliseconds(timeout);
475  for(;;) {
476  r = object_->cnt();
477  if((r >= minThr) && (r <= maxThr)) break;
478  if(!object_->wait(etime)) break;
479  };
480  object_->unlock();
481  return r;
482  }
483 
484  };
485 
487 
490  private:
491  int counter_;
492  bool cancel_;
493  Glib::Cond cond_;
494  Glib::Mutex lock_;
495  public:
496  ThreadRegistry(void);
497  ~ThreadRegistry(void);
499  void RegisterThread(void);
501  void UnregisterThread(void);
503 
504  bool WaitOrCancel(int timeout);
506 
508  bool WaitForExit(int timeout = -1);
510  void RequestCancel(void);
512 
513  void forceReset(void) {
514  counter_ = 0;
515  cancel_ = false;
516  lock_.unlock();
517  }
518  };
519 
522  void GlibThreadInitialize(void);
525 
527  public:
530  GlibThreadInitialize();
531  }
533 
534  void forceReset(void);
536 
538  void waitExit(void);
539  };
540 
541  // This is done intentionally to make sure glibmm is
542  // properly initialized before every module starts
543  // using threads functionality. To make it work this
544  // header must be included before defining any
545  // variable/class instance using static threads-related
546  // elements. The simplest way to do that is to use
547  // this header instead of glibmm/thread.h
548  static ThreadInitializer _local_thread_initializer;
549 
552 } // namespace Arc
553 
554 #endif /* __ARC_THREAD_H__ */