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 
42  class ThreadId {
43  private:
44  Glib::Mutex mutex;
45  std::map<unsigned long int, unsigned long int> thread_ids;
46  unsigned long int thread_no;
47  ThreadId();
48  public:
49  static ThreadId& getInstance();
51  void add();
53  void remove();
55  unsigned long int get();
56  };
59  class ThreadData;
60 
62 
67  friend class ThreadData;
68  private:
69  ThreadDataItem(const ThreadDataItem& it);
70  protected:
71  virtual ~ThreadDataItem(void);
72  public:
74 
75  ThreadDataItem(void);
77 
79  ThreadDataItem(std::string& key);
81  ThreadDataItem(const std::string& key);
83 
86  void Attach(std::string& key);
88 
90  void Attach(const std::string& key);
92 
93  static ThreadDataItem* Get(const std::string& key);
95 
99  virtual void Dup(void);
100  };
101 
103 
106  private:
107  Glib::Cond cond_;
108  Glib::Mutex lock_;
109  unsigned int flag_;
110  unsigned int waiting_;
111  public:
112  SimpleCondition(void)
113  : flag_(0), waiting_(0) {}
114  ~SimpleCondition(void) {
115  /* race condition ? */
116  broadcast();
117  }
119  void lock(void) {
120  lock_.lock();
121  }
123  void unlock(void) {
124  lock_.unlock();
125  }
127  void signal(void) {
128  lock_.lock();
129  flag_ = 1;
130  cond_.signal();
131  lock_.unlock();
132  }
134 
135  void signal_nonblock(void) {
136  flag_ = 1;
137  cond_.signal();
138  }
140 
141  void broadcast(void) {
142  lock_.lock();
143  flag_ = waiting_?waiting_:1;
144  cond_.broadcast();
145  lock_.unlock();
146  }
148  void wait(void) {
149  lock_.lock();
150  ++waiting_;
151  while (!flag_) cond_.wait(lock_);
152  --waiting_;
153  --flag_;
154  lock_.unlock();
155  }
157 
158  void wait_nonblock(void) {
159  ++waiting_;
160  while (!flag_) cond_.wait(lock_);
161  --waiting_;
162  --flag_;
163  }
165 
166  bool wait(int t) {
167  lock_.lock();
168  Glib::TimeVal etime;
169  etime.assign_current_time();
170  etime.add_milliseconds(t);
171  bool res(true);
172  ++waiting_;
173  while (!flag_) {
174  res = cond_.timed_wait(lock_, etime);
175  if (!res) break;
176  }
177  --waiting_;
178  if(res) --flag_;
179  lock_.unlock();
180  return res;
181  }
183  void reset(void) {
184  lock_.lock();
185  flag_ = 0;
186  lock_.unlock();
187  }
189 
190  void forceReset(void) {
191  flag_ = 0;
192  waiting_ = 0;
193  lock_.unlock();
194  }
195  };
196 
198 
201  private:
202  Glib::Cond cond_;
203  Glib::Mutex lock_;
204  int count_;
205  public:
206  SimpleCounter(void) : count_(0) {}
207  virtual ~SimpleCounter(void);
209 
210  virtual int inc(void);
212 
213  virtual int dec(void);
215  virtual int get(void) const;
217 
218  virtual int set(int v);
220  virtual void wait(void) const;
222 
224  virtual bool wait(int t) const;
226 
227  virtual void forceReset(void) {
228  lock_.unlock();
229  }
230  };
231 
233 
234  class TimedMutex {
235  private:
236  Glib::Cond cond_;
237  Glib::Mutex lock_;
238  bool locked_;
239  public:
240  TimedMutex(void):locked_(false) { };
241  ~TimedMutex(void) { };
243 
244  bool lock(int t = -1) {
245  lock_.lock();
246  if(t < 0) { // infinite
247  while(locked_) {
248  cond_.wait(lock_);
249  };
250  } else if(t > 0) { // timed
251  Glib::TimeVal etime;
252  etime.assign_current_time();
253  etime.add_milliseconds(t);
254  while(locked_) {
255  if(!cond_.timed_wait(lock_, etime)) break;
256  };
257  };
258  bool res = !locked_;
259  locked_=true;
260  lock_.unlock();
261  return res;
262  };
264  bool trylock(void) {
265  return lock(0);
266  };
268  bool unlock(void) {
269  lock_.lock();
270  bool res = locked_;
271  if(res) {
272  locked_ = false;
273  cond_.signal();
274  };
275  lock_.unlock();
276  return true;
277  };
279 
280  void forceReset(void) {
281  locked_ = false;
282  lock_.unlock();
283  }
284  };
285 
287 
288  class SharedMutex {
289  private:
290  Glib::Cond cond_;
291  Glib::Mutex lock_;
292  unsigned int exclusive_;
293  Glib::Thread* thread_;
294  typedef std::map<Glib::Thread*,unsigned int> shared_list;
295  shared_list shared_;
296  void add_shared_lock(void);
297  void remove_shared_lock(void);
298  bool have_shared_lock(void);
299  inline bool have_exclusive_lock(void) {
300  if(!exclusive_) return false;
301  if(thread_ == Glib::Thread::self()) return false;
302  return true;
303  };
304  public:
305  SharedMutex(void):exclusive_(0),thread_(NULL) { };
306  ~SharedMutex(void) { };
308  void lockShared(void);
310  void unlockShared(void);
312  bool isLockShared(void) {
313  return (shared_.size() > 0); // Is it safe?
314  };
316  void lockExclusive(void);
318  void unlockExclusive(void);
320  bool isLockExclusive(void) {
321  return (exclusive_ > 0);
322  };
324 
325  void forceReset(void) {
326  exclusive_ = 0;
327  thread_ = NULL;
328  shared_.clear();
329  lock_.unlock();
330  };
331  };
332 
335  class ThreadedPointerBase {
336  private:
337  Glib::Mutex lock_;
338  Glib::Cond cond_;
339  unsigned int cnt_;
340  void *ptr_;
341  bool released_;
342  ThreadedPointerBase(ThreadedPointerBase&);
343  ~ThreadedPointerBase(void);
344  public:
345  ThreadedPointerBase(void *p);
346  ThreadedPointerBase* add(void);
347  void* rem(void);
348  void* ptr(void) const { return ptr_; };
349  void rel(void) { released_ = true; };
350  unsigned int cnt(void) const { return cnt_; };
351  void lock(void) { lock_.lock(); };
352  void unlock(void) { lock_.unlock(); };
353  void wait(void) { cond_.wait(lock_); };
354  bool wait(Glib::TimeVal etime) {
355  return cond_.timed_wait(lock_,etime);
356  };
357  };
360 
361 
366  template<typename T>
368  private:
369  ThreadedPointerBase *object_;
370  public:
371  ThreadedPointer(T *p)
372  : object_(new ThreadedPointerBase(p)) {}
374  : object_(p.object_->add()) {}
375  ThreadedPointer(void)
376  : object_(new ThreadedPointerBase(NULL)) {}
377  ~ThreadedPointer(void) {
378  delete((T*)(object_->rem()));
379  }
382  if (p != object_->ptr()) {
383  delete((T*)(object_->rem()));
384  object_ = new ThreadedPointerBase(p);
385  }
386  return *this;
387  }
390  if (p.object_->ptr() != object_->ptr()) {
391  delete((T*)(object_->rem()));
392  object_ = p.object_->add();
393  }
394  return *this;
395  }
397  T& operator*(void) const {
398  return *(T*)(object_->ptr());
399  }
401  T* operator->(void) const {
402  return (T*)(object_->ptr());
403  }
405  operator bool(void) const {
406  return ((object_->ptr()) != NULL);
407  }
409  bool operator!(void) const {
410  return ((object_->ptr()) == NULL);
411  }
413  bool operator==(const ThreadedPointer& p) const {
414  return ((T*)(object_->ptr()) == (T*)(p.object_->ptr()));
415  }
417  bool operator!=(const ThreadedPointer& p) const {
418  return ((T*)(object_->ptr()) != (T*)(p.object_->ptr()));
419  }
421  bool operator<(const ThreadedPointer& p) const {
422  return ((T*)(object_->ptr()) < (T*)(p.object_->ptr()));
423  }
425  T* Ptr(void) const {
426  return (T*)(object_->ptr());
427  }
429 
431  T* Release(void) {
432  T* tmp = (T*)(object_->ptr());
433  object_->rel();
434  return tmp;
435  }
437  unsigned int Holders(void) {
438  return object_->cnt();
439  }
441  /* Returns current number of instances. */
442  unsigned int WaitOutRange(unsigned int minThr, unsigned int maxThr) {
443  unsigned int r = 0;
444  object_->lock();
445  for(;;) {
446  r = object_->cnt();
447  if(r <= minThr) break;
448  if(r >= maxThr) break;
449  object_->wait();
450  };
451  object_->unlock();
452  return r;
453  }
455 
457  unsigned int WaitOutRange(unsigned int minThr, unsigned int maxThr, int timeout) {
458  if(timeout < 0) return WaitOutRange(minThr, maxThr);
459  unsigned int r = 0;
460  object_->lock();
461  Glib::TimeVal etime;
462  etime.assign_current_time();
463  etime.add_milliseconds(timeout);
464  for(;;) {
465  r = object_->cnt();
466  if(r <= minThr) break;
467  if(r >= maxThr) break;
468  if(!object_->wait(etime)) break;
469  };
470  object_->unlock();
471  return r;
472  }
474  /* Returns current number of instances. */
475  unsigned int WaitInRange(unsigned int minThr, unsigned int maxThr) {
476  unsigned int r = 0;
477  object_->lock();
478  for(;;) {
479  r = object_->cnt();
480  if((r >= minThr) && (r <= maxThr)) break;
481  object_->wait();
482  };
483  object_->unlock();
484  return r;
485  }
487 
489  unsigned int WaitInRange(unsigned int minThr, unsigned int maxThr, int timeout) {
490  if(timeout < 0) return WaitInRange(minThr, maxThr);
491  unsigned int r = 0;
492  object_->lock();
493  Glib::TimeVal etime;
494  etime.assign_current_time();
495  etime.add_milliseconds(timeout);
496  for(;;) {
497  r = object_->cnt();
498  if((r >= minThr) && (r <= maxThr)) break;
499  if(!object_->wait(etime)) break;
500  };
501  object_->unlock();
502  return r;
503  }
504 
505  };
506 
508 
511  private:
512  int counter_;
513  bool cancel_;
514  Glib::Cond cond_;
515  Glib::Mutex lock_;
516  public:
517  ThreadRegistry(void);
518  ~ThreadRegistry(void);
520  void RegisterThread(void);
522  void UnregisterThread(void);
524 
525  bool WaitOrCancel(int timeout);
527 
529  bool WaitForExit(int timeout = -1);
531  void RequestCancel(void);
533 
534  void forceReset(void) {
535  counter_ = 0;
536  cancel_ = false;
537  lock_.unlock();
538  }
539  };
540 
543  void GlibThreadInitialize(void);
546 
548  public:
551  GlibThreadInitialize();
552  }
554 
555  void forceReset(void);
557 
559  void waitExit(void);
560  };
561 
562  // This is done intentionally to make sure glibmm is
563  // properly initialized before every module starts
564  // using threads functionality. To make it work this
565  // header must be included before defining any
566  // variable/class instance using static threads-related
567  // elements. The simplest way to do that is to use
568  // this header instead of glibmm/thread.h
569  static ThreadInitializer _local_thread_initializer;
570 
573 } // namespace Arc
574 
575 #endif /* __ARC_THREAD_H__ */