SGL
gthread.h
1 /*
2  * File: gthread.h
3  * ---------------
4  *
5  * This file contains code related to multithreading.
6  * Qt requires at least two threads to run: a main Qt GUI thread,
7  * and a separate student code thread.
8  * The student's main() function runs in this latter student thread.
9  * You can also run code in a new thread using the static method
10  * GThread::runInNewThread or GThread::runInNewThreadAsync.
11  *
12  * @version 2021/04/09
13  * - added sgl namespace
14  * @version 2021/04/03
15  * - removed dependency on custom collections
16  * @version 2019/04/13
17  * - reimplement GThread to wrap either QThread or std::thread
18  * - add GThread abstract base class for thread abstractions
19  * - add GThreadQt and GThreadStd subclasses
20  * - rename GFunctionThread to QFunctionThread to reduce name confusion
21  * - remove GStudentThread subclass and combine functionality into GThread
22  * @version 2018/10/18
23  * - improved thread names
24  * @version 2018/09/08
25  * - added doc comments for new documentation generation
26  * @version 2018/08/23
27  * - renamed to gthread.h to replace Java version
28  * @version 2018/07/28
29  * - initial version
30  */
31 
32 #ifndef _gthread_h
33 #define _gthread_h
34 
35 #include <QThread>
36 #include <atomic>
37 #include <map>
38 #include <thread>
39 
40 #include "gtypes.h"
41 
42 namespace sgl {
43 
44 class QtGui;
45 
60 class QFunctionThread : public QThread {
61 public:
65  QFunctionThread(GThunk func);
66 
70  QFunctionThread(GThunkInt func);
71 
75  int returnValue() const;
76 
77 protected:
81  void run();
82 
83 private:
84  Q_DISABLE_COPY(QFunctionThread)
85 
86  GThunk _func;
87  GThunkInt _funcInt;
88  bool _hasReturn;
89  int _returnValue;
90 };
91 
115 class GThread {
116 public:
123  virtual int getResult() const = 0;
124 
128  virtual bool isRunning() const = 0;
129 
134  virtual void join() = 0;
135 
141  virtual bool join(unsigned long ms) = 0;
142 
148  virtual string name() const = 0;
149 
155  virtual int priority() const = 0;
156 
161  virtual void setName(const string& name) = 0;
162 
167  virtual void setPriority(int priority) = 0;
168 
173  virtual void sleep(double ms) = 0;
174 
178  virtual void start() = 0;
179 
185  virtual void stop() = 0;
186 
194  virtual void yield() = 0;
195 
196  // TODO: methods to set a top-level exception handler
197 
198 
203  static void ensureThatThisIsTheQtGuiThread(const string& message = "");
204 
208  static GThread* getCurrentThread();
209 
214  static GThread* getQtGuiThread();
215 
220  static GThread* getStudentThread();
221 
225  static bool iAmRunningOnTheQtGuiThread();
226 
230  static bool iAmRunningOnTheStudentThread();
231 
236  static bool qtGuiThreadExists();
237 
250  static void runInNewThread(GThunk func, const string& threadName = "");
251 
266  static GThread* runInNewThreadAsync(GThunk func, const string& threadName = "");
267 
281  static void runOnQtGuiThread(GThunk func);
282 
293  static void runOnQtGuiThreadAsync(GThunk func);
294 
299  static void startStudentThread(GThunkInt mainFunc);
300 
304  static bool studentThreadExists();
305 
310  static bool wait(GThread* thread, long ms);
311 
319  static void setGuiThread();
320 
321 protected:
322  // forbid construction
323  GThread();
324  virtual ~GThread() = default;
325 
326  virtual void run() = 0;
327 
328  // member variables
333 
334  // pointers to the two core library threads
337 
338  // mapping between QThreads and their related GThread wrappings
339  static std::map<QThread*, GThread*> _allGThreadsQt;
340  static std::map<std::thread*, GThread*> _allGThreadsStd;
341 
342 private:
343  friend class QtGui;
344 };
345 
346 
363 class GThreadQt : public GThread {
364 public:
368  GThreadQt(GThunk func, const string& threadName = "");
369 
373  GThreadQt(GThunkInt func, const string& threadName = "");
374 
378  GThreadQt(QThread* qthread);
379 
380  virtual ~GThreadQt() override;
381 
382  /* @inherit */
383  int getResult() const override;
384 
385  /* @inherit */
386  bool isRunning() const override;
387 
388  /* @inherit */
389  void join() override;
390 
391  /* @inherit */
392  bool join(unsigned long ms) override;
393 
394  /* @inherit */
395  string name() const override;
396 
397  /* @inherit */
398  int priority() const override;
399 
400  /* @inherit */
401  void setName(const string& name) override;
402 
403  /* @inherit */
404  void setPriority(int priority) override;
405 
406  /* @inherit */
407  void sleep(double ms) override;
408 
409  /* @inherit */
410  void start() override;
411 
412  /* @inherit */
413  void stop() override;
414 
415  /* @inherit */
416  void yield() override;
417 
418 protected:
419  /* @inherit */
420  void run() override;
421 
422 private:
423  Q_DISABLE_COPY(GThreadQt)
424 
425  QThread* _qThread; // underlying real Qt thread
426 };
427 
428 
445 class GThreadStd : public GThread {
446 public:
450  GThreadStd(GThunk func, const string& threadName = "");
451 
455  GThreadStd(GThunkInt func, const string& threadName = "");
456 
460  GThreadStd(std::thread* stdThread);
461 
462  virtual ~GThreadStd() override;
463 
464  /* @inherit */
465  int getResult() const override;
466 
467  /* @inherit */
468  bool isRunning() const override;
469 
470  /* @inherit */
471  void join() override;
472 
473  /* @inherit */
474  bool join(unsigned long ms) override;
475 
476  /* @inherit */
477  string name() const override;
478 
479  /* @inherit */
480  int priority() const override;
481 
482  /* @inherit */
483  void setName(const string& name) override;
484 
485  /* @inherit */
486  void setPriority(int priority) override;
487 
488  /* @inherit */
489  void sleep(double ms) override;
490 
491  /* @inherit */
492  void start() override;
493 
494  /* @inherit */
495  void stop() override;
496 
497  /* @inherit */
498  void yield() override;
499 
500 protected:
501  /* @inherit */
502  void run() override;
503 
504 private:
505  Q_DISABLE_COPY(GThreadStd)
506 
507  std::thread* _stdThread; // underlying real std thread
508  string _name;
509  std::atomic<bool> _running;
510 };
511 
512 
513 // Platform-specific way to set the name of current thread for display in debugger
514 void native_set_thread_name(const char *name);
515 
516 // Platform-specific way to exit current thread
517 [[noreturn]] void native_thread_exit();
518 
519 } // namespace sgl
520 
521 #endif // _gthread_h
int _returnValue
Definition: gthread.h:332
friend class QtGui
Definition: gthread.h:343
static void runOnQtGuiThread(GThunk func)
Runs the given void function on the Qt GUI thread, blocking the current thread to wait until it is do...
Definition: gthread.cpp:152
std::function< int()> GThunkInt
An alias for a function wrapper around a function with no parameters and an int return (such as main(...
Definition: gtypes.h:36
virtual void start()=0
Tells the thread to start running.
static GThread * _qtGuiThread
Definition: gthread.h:335
GThread()
Definition: gthread.cpp:96
static bool wait(GThread *thread, long ms)
Waits the given number of milliseconds for the given thread to finish.
Definition: gthread.cpp:196
static GThread * getCurrentThread()
Returns the caller&#39;s Qt thread object.
Definition: gthread.cpp:107
virtual string name() const =0
Returns the thread&#39;s name as passed to the constructor, or a default name if none was passed...
GThunkInt _funcInt
Definition: gthread.h:330
static void ensureThatThisIsTheQtGuiThread(string message="")
Generates an error if the caller is not running on the Qt GUI thread.
Definition: gthread.cpp:100
static GThread * getQtGuiThread()
Returns the Qt thread object representing the Qt Gui thread for the application.
Definition: gthread.cpp:116
virtual int priority() const =0
Returns the thread&#39;s priority.
void native_set_thread_name(const char *name)
Definition: gthread.cpp:43
static GThread * _studentThread
Definition: gthread.h:336
Definition: console.h:45
virtual void setName(string name)=0
Sets the thread&#39;s name to the given value.
static void startStudentThread(GThunkInt mainFunc)
Starts the student&#39;s thread, telling it to run the given function, which accepts no arguments and ret...
Definition: gthread.cpp:185
virtual void run()=0
virtual void stop()=0
Forcibly terminates the thread.
static bool iAmRunningOnTheQtGuiThread()
Returns true if the caller is running on the Qt GUI thread.
Definition: gthread.cpp:124
virtual void setPriority(int priority)=0
Sets the thread&#39;s priority to the given value.
static bool iAmRunningOnTheStudentThread()
Returns true if the caller is running on the student thread.
Definition: gthread.cpp:128
static void runInNewThread(GThunk func, string threadName="")
Runs the given void function in its own new thread, blocking the current thread to wait until it is d...
Definition: gthread.cpp:136
GThunk _func
Definition: gthread.h:329
The GThread class is a utility class containing static methods that allow you to run code on various ...
Definition: gthread.h:115
static std::map< QThread *, GThread * > _allGThreadsQt
Definition: gthread.h:339
static void runOnQtGuiThreadAsync(GThunk func)
Runs the given void function on the Qt GUI thread in the background; the current thread does not bloc...
Definition: gthread.cpp:165
bool _hasReturn
Definition: gthread.h:331
virtual int getResult() const =0
Returns the value returned by the thread&#39;s function.
virtual void yield()=0
Indicates that the current thread is willing to yield execution to any other threads that want to run...
Definition: gthread.cpp:215
static GThread * getStudentThread()
Returns the Qt thread object representing the thread on which the student&#39;s main() function runs...
Definition: gthread.cpp:120
virtual ~GThread()=default
std::function< void()> GThunk
An alias for a function wrapper around a void function with no parameters and no return.
Definition: gtypes.h:30
static bool studentThreadExists()
Returns true if the student&#39;s thread has already been created.
Definition: gthread.cpp:192
virtual bool isRunning() const =0
Returns true if the given thread is currently actively running.
static bool qtGuiThreadExists()
Returns true if the Qt GUI thread has been created.
Definition: gthread.cpp:132
static GThread * runInNewThreadAsync(GThunk func, string threadName="")
Runs the given void function in its own new thread in the background; the current thread does not blo...
Definition: gthread.cpp:146
static std::map< std::thread *, GThread * > _allGThreadsStd
Definition: gthread.h:340
virtual void join()=0
Waits for this thread to finish.
void native_thread_exit()
Definition: gthread.cpp:57
virtual void sleep(double ms)=0
Causes the thread to pause itself for the given number of milliseconds.