gtkIOStream  1.7.0
GTK+ << C++ IOStream operators for GTK+. Now with ORBing, numerical computation, audio client and more ...
Thread.H
Go to the documentation of this file.
1 /* Copyright 2000-2018 Matt Flax <flatmax@flatmax.org>
2  This file is part of GTK+ IOStream class set
3 
4  GTK+ IOStream is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8 
9  GTK+ IOStream is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You have received a copy of the GNU General Public License
15  along with GTK+ IOStream
16  */
17 #ifndef THREAD_H_
18 #define THREAD_H_
19 
20 #ifdef USE_USE_GLIB_THREADS
21 #include <glib.h>
22 #else
23 #include <pthread.h>
24 #include <errno.h>
25 #include <stdio.h>
26 #endif
27 
28 #include <string.h>
29 #include "Debug.H"
30 
31 #define THREAD_CREATE_ERROR -0+THREAD_ERROR_OFFSET
32 #define THREAD_MUTEX_UNINIT_ERROR -1+THREAD_ERROR_OFFSET
33 #define THREAD_MUTEX_DEADLK_ERROR -2+THREAD_ERROR_OFFSET
34 #define THREAD_MUTEX_DONTOWN_ERROR -3+THREAD_ERROR_OFFSET
35 #define THREAD_MUTEX_DESTROY_LOCKED_ERROR -4+THREAD_ERROR_OFFSET
36 #define THREAD_MUTEX_LOCKBUSY_WARNING -5+THREAD_ERROR_OFFSET
37 #define THREAD_NOTFOUND_ERROR -6+THREAD_ERROR_OFFSET
38 #define THREAD_COND_WAITBUSY_ERROR -7+THREAD_ERROR_OFFSET
39 #define THREAD_SCHED_ERROR -8+THREAD_ERROR_OFFSET
40 
41 class ThreadDebug : public Debug {
42 public:
43  ThreadDebug(void) {
44 #ifndef NDEBUG
45  errors[THREAD_CREATE_ERROR]=std::string("The thread couldn't be started.");
46  errors[THREAD_MUTEX_UNINIT_ERROR]=std::string("The mutex has not been properly initialized.");
47  errors[THREAD_MUTEX_DEADLK_ERROR]=std::string("The mutex has already been locked. Deadlock error.");
48  errors[THREAD_MUTEX_DONTOWN_ERROR]=std::string("The mutex is not owned by the thread attempting to unlock, error.");
49  errors[THREAD_MUTEX_DESTROY_LOCKED_ERROR]=std::string("You are trying to destroy the mutex which is locked, error.");
50  errors[THREAD_MUTEX_LOCKBUSY_WARNING]=std::string("You are trying to lock a mutex which is already locked, you didn't acquire lock this time, try again.");
51  errors[THREAD_NOTFOUND_ERROR]=std::string("That thread couldn't be found.");
52  errors[THREAD_COND_WAITBUSY_ERROR]=std::string("One or more threads is waiting on the Cond variable. Can't destroy. ");
53  errors[THREAD_SCHED_ERROR]=std::string("Problem setting the scheduling. ");
54 
55 #endif
56  }
57 };
58 
63 class Thread {
64 
65 #ifdef USE_GLIB_THREADS
66  GThread* thread;
67  GError *threadErrorPtr;
68 #else
69  pthread_t thread;
70 #endif
71 
72 public:
75  Thread(void) {
76 #ifdef USE_GLIB_THREADS
77  thread=NULL;
78  threadErrorPtr=NULL;
79 #else
80  thread=0;
81 #endif
82  }
83 
86  virtual ~Thread(void) {
87 #ifdef USE_GLIB_THREADS
88  g_thread_join(thread);
89  thread=NULL;
90 #else
91 // void *retVal;
92  pthread_cancel(thread); // this returns error of ESRCH if the thread is already finished
93 
94 // int threadResp=pthread_join(thread, &retVal);
95  // on destruction, not interested in the return value here, just want to make sure the thread has exited.
96 // if (threadResp!=0) {
97 // errno=threadResp;
98 // perror("Thread::meetThread : Couldn't meet the thread");
99 // cerr<<"Most likely that the thread isn't running."<<endl;
100 // }
101 #endif
102  }
103 
107  void *stop(void){
108  int retVal = pthread_cancel(thread);
109  if (retVal==ESRCH)
110  ThreadDebug().evaluateError(THREAD_NOTFOUND_ERROR, " When trying to stop.");
111  return NULL;
112 
113  return meetThread();
114  }
115 
122 #ifdef USE_GLIB_THREADS
123  int run(void (*start_routine) (void *), void *data, int priority=0) {
124  priority=0;
125 #else
126  int run(void *(*start_routine) (void *), void *data, int priority=0) {
127 #endif
128 #ifdef USE_GLIB_THREADS
129  thread = g_thread_create((GThreadFunc)start_routine, (gpointer) data, TRUE, &threadErrorPtr);
130  if (thread==NULL)
131  return ThreadDebug().evaluateError(THREAD_CREATE_ERROR);
132 #else
133  pthread_attr_t attr; // by default assumed PTHREAD_EXPLICIT_SCHED
134  pthread_attr_init(&attr);
135  int threadResp=0;
136 
137  printf("entering set priority\n");
138  if (priority>0)
139  if (threadResp=setPriority(&attr, priority))
140  return threadResp;
141  printf("exited set priority\n");
142 
143  if (threadResp=pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE))
144  return ThreadDebug().evaluateError(threadResp, "Thread::run : Thread setting detatch state failed.");
145 // int pthread_setcanceltype(int type, int *oldtype);
146 
147  printf("create\n");
148  if (threadResp=pthread_create(&thread, &attr, start_routine, data))
149  return ThreadDebug().evaluateError(threadResp, "Thread::run : Thread creation failed.");
150 
151  pthread_attr_destroy(&attr);
152 
153  if (threadResp!=0)
154  return ThreadDebug().evaluateError(THREAD_CREATE_ERROR);
155 #endif
156  return 0;
157  }
158 
159 #ifndef USE_GLIB_THREADS
160  int setPriority(pthread_attr_t *attributes, int priority){
161  int res=0;
162  if ((res = pthread_attr_setinheritsched(attributes, PTHREAD_EXPLICIT_SCHED)))
163  return ThreadDebug().evaluateError(res, "Cannot request explicit scheduling for thread");
164 
165  if ((res = pthread_attr_setscope(attributes, PTHREAD_SCOPE_SYSTEM)))
166  return ThreadDebug().evaluateError(res, "Cannot set scheduling scope for thread");
167 
168  if ((res = pthread_attr_setschedpolicy(attributes, SCHED_FIFO)))
169  return ThreadDebug().evaluateError(res, "Cannot request schedule policy for thread");
170 
171  struct sched_param rt_param;
172  memset(&rt_param, 0, sizeof(rt_param));
173  rt_param.sched_priority = priority;
174  if ((res = pthread_attr_setschedparam(attributes, &rt_param)))
175  return ThreadDebug().evaluateError(res, "Cannot set scheduling priority for thread");
176 
177  return res;
178  }
179 
180  int getPriority(){
181  int res;
182  struct sched_param rt_param;
183  memset(&rt_param, 0, sizeof(rt_param));
184  int policy;
185  if ((res=pthread_getschedparam(thread, &policy, &rt_param)) != 0)
186  return ThreadDebug().evaluateError(res," Getting sched param.");
187  printf("Thread policy is %d priority is %d\n",policy, rt_param.sched_priority);
188  if (policy != SCHED_FIFO)
189  return ThreadDebug().evaluateError(THREAD_SCHED_ERROR, "Scheduling is NOT SCHED_FIFO!\n");
190  return rt_param.sched_priority;
191  }
192 #endif
193 
197  void *meetThread(void) {
198  if (thread) {
199 #ifdef USE_GLIB_THREADS
200  g_thread_join(thread);
201  thread=NULL;
202 #else
203  void *retVal;
204  int threadResp=pthread_join(thread, &retVal);
205  if (threadResp!=0) {
206  errno=threadResp;
207  perror("Thread::meetThread : Couldn't meet the thread");
208  }
209  thread=0;
210  return retVal;
211 #endif
212  }
213  return NULL;
214  }
215 
219  void exit(void *retVal) {
220 #ifndef USE_GLIB_THREADS
221  pthread_exit(retVal);
222 #endif
223  }
224 
228  bool running() {
229 #ifndef USE_GLIB_THREADS
230  return thread!=(int)NULL;
231 #else
232  return thread!=0;
233 #endif
234  }
235 };
236 
239 class ThreadedMethod : public Thread {
240 #ifdef USE_GLIB_THREADS
241 
243  static void threadMainStatic(void *data) {
244  static_cast<ThreadedMethod*>(data)->threadMain();
245  }
246 #else
247 
249  static void *threadMainStatic(void *data) {
250  return static_cast<ThreadedMethod*>(data)->threadMain();
251  }
252 #endif
253 public:
257  virtual void *threadMain(void)=0;
258 
263  virtual int run(int priority=0) {
264  return Thread::run(threadMainStatic, static_cast<void*>(this), priority);
265  }
266 };
267 
268 #ifndef USE_USE_GLIB_THREADS
269 
271 class Mutex {
272 protected:
273  pthread_mutex_t mut;
274 public:
278  Mutex() {
279  pthread_mutex_init(&mut, NULL); //defaults to a fast mutex PTHREAD_MUTEX_INITIALIZER
280  }
281 
284  virtual ~Mutex() {
285  pthread_mutex_destroy(&mut);
286 // int retVal=pthread_mutex_destroy(&mut);
287 // if (retVal!=0) // returned with error
288 // if (retVal==EBUSY)
289 // ThreadDebug().evaluateError(THREAD_MUTEX_DESTROY_LOCKED_ERROR);
290  }
291 
295  int lock() {
296  int retVal=pthread_mutex_lock(&mut);
297  if (retVal!=0) { // returned with error
298  if (retVal==EINVAL)
299  return ThreadDebug().evaluateError(THREAD_MUTEX_UNINIT_ERROR);
300  if (retVal==EDEADLK)
301  return ThreadDebug().evaluateError(THREAD_MUTEX_DEADLK_ERROR);
302 
303  }
304  return NO_ERROR;
305  }
306 
310  int tryLock() {
311  int retVal=pthread_mutex_trylock(&mut);
312  if (retVal!=0) { // returned with error
313  if (retVal==EINVAL)
314  return ThreadDebug().evaluateError(THREAD_MUTEX_UNINIT_ERROR);
315  if (retVal==EBUSY)
316  return ThreadDebug().evaluateError(THREAD_MUTEX_LOCKBUSY_WARNING);
317 
318  }
319  return NO_ERROR;
320  }
321 
325  int unLock() {
326  int retVal=pthread_mutex_unlock(&mut);
327  if (retVal!=0) { // returned with error
328  if (retVal==EINVAL)
329  return ThreadDebug().evaluateError(THREAD_MUTEX_UNINIT_ERROR);
330  if (retVal==EPERM) // this result is returned from error checking mutexes only
331  return ThreadDebug().evaluateError(THREAD_MUTEX_DONTOWN_ERROR);
332 
333  }
334  return NO_ERROR;
335  }
336 };
337 
340 class Cond : public Mutex {
341  pthread_cond_t cond;
342 public:
344  Cond(){
345  // pthread_condattr_t cond_attr; // currently not used
346  pthread_cond_init(&cond, NULL);
347  }
348 
350  virtual ~Cond(){
351  // pthread_condattr_t cond_attr; // currently not used
352  int retVal = pthread_cond_destroy(&cond);
353  if (retVal==EBUSY)
354  ThreadDebug().evaluateError(THREAD_COND_WAITBUSY_ERROR);
355  }
356 
361  void wait(){
362  pthread_cond_wait(&cond, &mut);
363  }
364 
369  void signal(){
370  pthread_cond_signal(&cond);
371  }
372 
377  void boroadcast(){
378  pthread_cond_broadcast(&cond);
379  }
380 };
381 
440 public:
442 
443  virtual ~WaitingThread(void){
444  cond.lock(); // signal the waiting thread so it isn't waiting and it is possible to shutdown.
445  cond.signal();
446  // don't unlock so that the waiting thread can't enter again during shutdown ... don't call here cond.unLock();
447  }
448 };
449 #endif // ifndef USE_USE_GLIB_THREADS
450 
451 #endif // THREAD_H_
virtual ~Cond()
Destructor.
Definition: Thread.H:350
Mutex()
Definition: Thread.H:278
#define THREAD_MUTEX_UNINIT_ERROR
The mutex wasn&#39;t initialised error.
Definition: Thread.H:32
int setPriority(pthread_attr_t *attributes, int priority)
Definition: Thread.H:160
void signal()
Definition: Thread.H:369
#define THREAD_MUTEX_DONTOWN_ERROR
The thread doesn&#39;t own the mutex.
Definition: Thread.H:34
pthread_cond_t cond
The POSIX condition variable.
Definition: Thread.H:341
ThreadDebug(void)
Definition: Thread.H:43
Definition: Thread.H:340
#define THREAD_MUTEX_LOCKBUSY_WARNING
The mutex can&#39;t be locked as it is already locked.
Definition: Thread.H:36
Definition: Thread.H:271
bool running()
Definition: Thread.H:228
int getPriority()
Definition: Thread.H:180
#define THREAD_COND_WAITBUSY_ERROR
One or more threads is waiting on the Cond variable.
Definition: Thread.H:38
std::map< int, std::string > errors
This will contain a map between error numbers and descriptive std::strings for the errors...
Definition: Debug.H:115
virtual ~Thread(void)
Definition: Thread.H:86
#define NO_ERROR
There is no error.
Definition: Debug.H:33
virtual int run(int priority=0)
Definition: Thread.H:263
void * meetThread(void)
Definition: Thread.H:197
#define THREAD_MUTEX_DEADLK_ERROR
The mutex is already locked.
Definition: Thread.H:33
int run(void *(*start_routine)(void *), void *data, int priority=0)
Definition: Thread.H:126
#define THREAD_CREATE_ERROR
Couldn&#39;t create the thread error.
Definition: Thread.H:31
#define THREAD_SCHED_ERROR
Scheduling setting error.
Definition: Thread.H:39
int tryLock()
Definition: Thread.H:310
int unLock()
Definition: Thread.H:325
pthread_t thread
The thread structure.
Definition: Thread.H:69
Cond cond
Definition: Thread.H:441
void boroadcast()
Definition: Thread.H:377
pthread_mutex_t mut
The POSIX mutex semaphore.
Definition: Thread.H:273
void * stop(void)
Definition: Thread.H:107
Definition: Thread.H:63
Definition: Debug.H:112
static void * threadMainStatic(void *data)
Definition: Thread.H:249
void wait()
Definition: Thread.H:361
#define THREAD_NOTFOUND_ERROR
The thread can&#39;t be found.
Definition: Thread.H:37
Cond()
Constructor.
Definition: Thread.H:344
void exit(void *retVal)
Definition: Thread.H:219
virtual ~WaitingThread(void)
Definition: Thread.H:443
int lock()
Definition: Thread.H:295
Thread(void)
Definition: Thread.H:75
#define THREAD_MUTEX_DESTROY_LOCKED_ERROR
The mutex can&#39;t be destroyed when locked.
Definition: Thread.H:35
virtual ~Mutex()
Definition: Thread.H:284
gtkIOStream: /tmp/gtkiostream/include/Thread.H Source File
GTK+ IOStream  Beta