libt3widget
thread.h
1 /* Copyright (C) 2015 G.P. Halkes
2  This program is free software: you can redistribute it and/or modify
3  it under the terms of the GNU General Public License version 3, as
4  published by the Free Software Foundation.
5 
6  This program is distributed in the hope that it will be useful,
7  but WITHOUT ANY WARRANTY; without even the implied warranty of
8  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9  GNU General Public License for more details.
10 
11  You should have received a copy of the GNU General Public License
12  along with this program. If not, see <http://www.gnu.org/licenses/>.
13 */
14 
15 #ifndef T3_WIDGET_THREAD_H
16 #define T3_WIDGET_THREAD_H
17 
18 /* This header file provides a set of types in the t3_widget::thread namespace which
19  use interfaces sufficiently similar to the C++11 versions of the types with the
20  same name. The underlying idea is to remove the need for a pthread library, using
21  only the types available in C++11. Only the parts of the std:: interface that is
22  actually used is implemented. In one case (std::condition_variable::wait_until)
23  the choice was made not to reimplement part of the standard. This does mean that
24  we can not use "namespace thread = std" in the C++11 case, which would otherwise
25  be possible.
26 
27  Note that some parts of the interface may actually have different semantics for
28  some use cases that are not used in libt3widget.
29 */
30 
31 #ifndef _T3_WIDGET_INTERNAL
32 #error This header file is for internal use _only_!!
33 #endif
34 
35 #if __cplusplus >= 201103L
36 #include <chrono>
37 #include <condition_variable>
38 #include <mutex>
39 #include <thread>
40 namespace t3_widget {
41 namespace thread {
42 using mutex = std::mutex;
43 using thread = std::thread;
44 namespace this_thread = std::this_thread;
45 template <typename T> using unique_lock = std::unique_lock<T>;
46 using defer_lock_t = std::defer_lock_t;
47 using condition_variable = std::condition_variable;
48 using cv_status = std::cv_status;
49 using timeout_t = std::chrono::time_point<std::chrono::system_clock>;
50 inline timeout_t timeout_time(int microseconds) {
51  return std::chrono::system_clock::now() + std::chrono::microseconds(microseconds);
52 }
53 } // namespace thread
54 } // namespace t3_widget
55 #else
56 #include <errno.h>
57 #include <pthread.h>
58 #include <sys/time.h>
59 namespace t3_widget {
60 namespace thread {
61 class thread {
62 public:
63  thread() {}
64  thread(void (*f)()) { pthread_create(&handle, NULL, wrap_function, reinterpret_cast<void *>(f)); }
65  void join() { void *result; pthread_join(handle, &result); }
66  const thread &operator=(const thread &other) { handle = other.handle; return *this; }
67 
68 private:
69  static void *wrap_function(void *f) { reinterpret_cast<void (*)()>(f)(); return NULL; }
70  pthread_t handle;
71 };
72 
73 namespace this_thread {
74 inline void yield() { pthread_yield(); }
75 } // namespace this_thread
76 
77 typedef struct timespec timeout_t;
78 inline timeout_t timeout_time(int microseconds) {
79  struct timeval timeval;
80  struct timespec result;
81 
82  gettimeofday(&timeval, NULL);
83  timeval.tv_sec += microseconds / 1000000;
84  timeval.tv_usec += microseconds % 1000000;
85  if (timeval.tv_usec > 1000000) {
86  timeval.tv_sec++;
87  timeval.tv_usec -= 1000000;
88  }
89  result.tv_sec = timeval.tv_sec;
90  result.tv_nsec = (long) timeval.tv_usec * 1000;
91  return result;
92 }
93 
94 class mutex {
95 public:
96  mutex() { pthread_mutex_init(&mtx, NULL); }
97  ~mutex() { pthread_mutex_destroy(&mtx); }
98 
99  void lock() { pthread_mutex_lock(&mtx); }
100  void unlock() { pthread_mutex_unlock(&mtx); }
101 
102 private:
103  friend class condition_variable;
104  pthread_mutex_t mtx;
105 };
106 
107 struct defer_lock_t { };
108 
109 template <class T>
110 class unique_lock {
111 public:
112  unique_lock(T &m) : locked(true), mtx(m) { mtx.lock(); }
113  unique_lock(T &m, defer_lock_t t) : locked(false), mtx(m) { (void) t; }
114  ~unique_lock() { if (locked) mtx.unlock(); }
115  void lock() { mtx.lock(); locked = true; }
116  void unlock() { mtx.unlock(); locked = false; }
117 private:
118  friend class condition_variable;
119  bool locked;
120  T &mtx;
121 };
122 
123 struct cv_status {
124  enum {
125  no_timeout,
126  timeout
127  };
128 };
129 
131 public:
132  condition_variable() { pthread_cond_init(&cond, NULL); }
133  ~condition_variable() { pthread_cond_destroy(&cond); }
134 
135  void notify_one() { pthread_cond_signal(&cond); }
136  void notify_all() { pthread_cond_broadcast(&cond); }
137  void wait(unique_lock<mutex> &lock) { pthread_cond_wait(&cond, &lock.mtx.mtx); }
138 
139  // This function has a different signature, because reimplementing all the
140  // time related stuff in the C++11 standard is too much. Instead, we define
141  // a new type (timeout_t) and a function to calculate those.
142  int wait_until(unique_lock<mutex> &lock, const timeout_t &timeout) {
143  return pthread_cond_timedwait(&cond, &lock.mtx.mtx, &timeout) == ETIMEDOUT ? cv_status::timeout : cv_status::no_timeout;
144  }
145 
146 private:
147  pthread_cond_t cond;
148 };
149 } // namespace thread
150 } // namespace t3_widget
151 #endif
152 
153 #endif
154 
The t3_widget namespace is contains all classes, functions and global variables in the libt3widget li...
Definition: autocompleter.cc:18
Definition: thread.h:61
Definition: thread.h:123
Definition: thread.h:107
Definition: thread.h:110
Definition: thread.h:94