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/03
13  * - removed dependency on custom collections
14  * @version 2019/04/13
15  * - reimplement GThread to wrap either QThread or std::thread
16  * - add GThread abstract base class for thread abstractions
17  * - add GThreadQt and GThreadStd subclasses
18  * - rename GFunctionThread to QFunctionThread to reduce name confusion
19  * - remove GStudentThread subclass and combine functionality into GThread
20  * @version 2018/10/18
21  * - improved thread names
22  * @version 2018/09/08
23  * - added doc comments for new documentation generation
24  * @version 2018/08/23
25  * - renamed to gthread.h to replace Java version
26  * @version 2018/07/28
27  * - initial version
28  */
29 
30 #ifndef _gthread_h
31 #define _gthread_h
32 
33 #include <QThread>
34 #include <atomic>
35 #include <map>
36 #include <thread>
37 
38 #include "gtypes.h"
39 
40 class QtGui;
41 
56 class QFunctionThread : public QThread {
57 public:
61  QFunctionThread(GThunk func);
62 
66  QFunctionThread(GThunkInt func);
67 
71  int returnValue() const;
72 
73 protected:
77  void run();
78 
79 private:
80  Q_DISABLE_COPY(QFunctionThread)
81 
82  GThunk _func;
83  GThunkInt _funcInt;
84  bool _hasReturn;
85  int _returnValue;
86 };
87 
111 class GThread {
112 public:
119  virtual int getResult() const = 0;
120 
124  virtual bool isRunning() const = 0;
125 
130  virtual void join() = 0;
131 
137  virtual bool join(unsigned long ms) = 0;
138 
144  virtual string name() const = 0;
145 
151  virtual int priority() const = 0;
152 
157  virtual void setName(const string& name) = 0;
158 
163  virtual void setPriority(int priority) = 0;
164 
169  virtual void sleep(double ms) = 0;
170 
174  virtual void start() = 0;
175 
181  virtual void stop() = 0;
182 
190  virtual void yield() = 0;
191 
192  // TODO: methods to set a top-level exception handler
193 
194 
199  static void ensureThatThisIsTheQtGuiThread(const string& message = "");
200 
204  static GThread* getCurrentThread();
205 
210  static GThread* getQtGuiThread();
211 
216  static GThread* getStudentThread();
217 
221  static bool iAmRunningOnTheQtGuiThread();
222 
226  static bool iAmRunningOnTheStudentThread();
227 
232  static bool qtGuiThreadExists();
233 
246  static void runInNewThread(GThunk func, const string& threadName = "");
247 
262  static GThread* runInNewThreadAsync(GThunk func, const string& threadName = "");
263 
277  static void runOnQtGuiThread(GThunk func);
278 
289  static void runOnQtGuiThreadAsync(GThunk func);
290 
295  static void startStudentThread(GThunkInt mainFunc);
296 
300  static bool studentThreadExists();
301 
306  static bool wait(GThread* thread, long ms);
307 
315  static void setGuiThread();
316 
317 protected:
318  // forbid construction
319  GThread();
320  virtual ~GThread() = default;
321 
322  virtual void run() = 0;
323 
324  // member variables
325  GThunk _func;
326  GThunkInt _funcInt;
329 
330  // pointers to the two core library threads
333 
334  // mapping between QThreads and their related GThread wrappings
335  static std::map<QThread*, GThread*> _allGThreadsQt;
336  static std::map<std::thread*, GThread*> _allGThreadsStd;
337 
338 
339 
340 private:
341  friend class QtGui;
342 };
343 
344 
361 class GThreadQt : public GThread {
362 public:
366  GThreadQt(GThunk func, const string& threadName = "");
367 
371  GThreadQt(GThunkInt func, const string& threadName = "");
372 
376  GThreadQt(QThread* qthread);
377 
378  virtual ~GThreadQt() override;
379 
380  /* @inherit */
381  int getResult() const override;
382 
383  /* @inherit */
384  bool isRunning() const override;
385 
386  /* @inherit */
387  void join() override;
388 
389  /* @inherit */
390  bool join(unsigned long ms) override;
391 
392  /* @inherit */
393  string name() const override;
394 
395  /* @inherit */
396  int priority() const override;
397 
398  /* @inherit */
399  void setName(const string& name) override;
400 
401  /* @inherit */
402  void setPriority(int priority) override;
403 
404  /* @inherit */
405  void sleep(double ms) override;
406 
407  /* @inherit */
408  void start() override;
409 
410  /* @inherit */
411  void stop() override;
412 
413  /* @inherit */
414  void yield() override;
415 
416 protected:
417  /* @inherit */
418  void run() override;
419 
420 private:
421  Q_DISABLE_COPY(GThreadQt)
422 
423  QThread* _qThread; // underlying real Qt thread
424 };
425 
426 
443 class GThreadStd : public GThread {
444 public:
448  GThreadStd(GThunk func, const string& threadName = "");
449 
453  GThreadStd(GThunkInt func, const string& threadName = "");
454 
458  GThreadStd(std::thread* stdThread);
459 
460  virtual ~GThreadStd() override;
461 
462  /* @inherit */
463  int getResult() const override;
464 
465  /* @inherit */
466  bool isRunning() const override;
467 
468  /* @inherit */
469  void join() override;
470 
471  /* @inherit */
472  bool join(unsigned long ms) override;
473 
474  /* @inherit */
475  string name() const override;
476 
477  /* @inherit */
478  int priority() const override;
479 
480  /* @inherit */
481  void setName(const string& name) override;
482 
483  /* @inherit */
484  void setPriority(int priority) override;
485 
486  /* @inherit */
487  void sleep(double ms) override;
488 
489  /* @inherit */
490  void start() override;
491 
492  /* @inherit */
493  void stop() override;
494 
495  /* @inherit */
496  void yield() override;
497 
498 protected:
499  /* @inherit */
500  void run() override;
501 
502 private:
503  Q_DISABLE_COPY(GThreadStd)
504 
505  std::thread* _stdThread; // underlying real std thread
506  string _name;
507  std::atomic<bool> _running;
508 };
509 
510 
511 // Platform-specific way to set the name of current thread for display in debugger
512 void native_set_thread_name(const char *name);
513 
514 // Platform-specific way to exit current thread
515 [[noreturn]] void native_thread_exit();
516 
517 #endif // _gthread_h
virtual void sleep(double ms)=0
Causes the thread to pause itself for the given number of milliseconds.
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:132
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:181
virtual int getResult() const =0
Returns the value returned by the thread&#39;s function.
virtual void setPriority(int priority)=0
Sets the thread&#39;s priority to the given value.
virtual void join()=0
Waits for this thread to finish.
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:161
virtual ~GThread()=default
friend class QtGui
Definition: gthread.h:341
virtual int priority() const =0
Returns the thread&#39;s priority.
virtual void setName(string name)=0
Sets the thread&#39;s name to the given value.
static GThread * getQtGuiThread()
Returns the Qt thread object representing the Qt Gui thread for the application.
Definition: gthread.cpp:112
static GThread * getStudentThread()
Returns the Qt thread object representing the thread on which the student&#39;s main() function runs...
Definition: gthread.cpp:116
static void ensureThatThisIsTheQtGuiThread(string message="")
Generates an error if the caller is not running on the Qt GUI thread.
Definition: gthread.cpp:96
static GThread * _qtGuiThread
Definition: gthread.h:331
static GThread * getCurrentThread()
Returns the caller&#39;s Qt thread object.
Definition: gthread.cpp:103
GThunkInt _funcInt
Definition: gthread.h:326
static bool iAmRunningOnTheQtGuiThread()
Returns true if the caller is running on the Qt GUI thread.
Definition: gthread.cpp:120
virtual string name() const =0
Returns the thread&#39;s name as passed to the constructor, or a default name if none was passed...
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:211
static bool qtGuiThreadExists()
Returns true if the Qt GUI thread has been created.
Definition: gthread.cpp:128
static bool wait(GThread *thread, long ms)
Waits the given number of milliseconds for the given thread to finish.
Definition: gthread.cpp:192
int _returnValue
Definition: gthread.h:328
virtual void stop()=0
Forcibly terminates the thread.
GThread()
Definition: gthread.cpp:92
GThunk _func
Definition: gthread.h:325
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:142
bool _hasReturn
Definition: gthread.h:327
virtual void run()=0
static GThread * _studentThread
Definition: gthread.h:332
static bool studentThreadExists()
Returns true if the student&#39;s thread has already been created.
Definition: gthread.cpp:188
virtual void start()=0
Tells the thread to start running.
static std::map< std::thread *, GThread * > _allGThreadsStd
Definition: gthread.h:336
virtual bool isRunning() const =0
Returns true if the given thread is currently actively running.
static bool iAmRunningOnTheStudentThread()
Returns true if the caller is running on the student thread.
Definition: gthread.cpp:124
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:148
static std::map< QThread *, GThread * > _allGThreadsQt
Definition: gthread.h:335
The GThread class is a utility class containing static methods that allow you to run code on various ...
Definition: gthread.h:111