-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #143 from oblivioncth/implementation/general_worke…
…r_thread Add general worker thread to minimize threads started by lib
- Loading branch information
Showing
3 changed files
with
142 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
// Unit Include | ||
#include "qx-generalworkerthread.h" | ||
|
||
// Qt Includes | ||
#include <QCoreApplication> | ||
|
||
/*! @cond */ | ||
namespace Qx | ||
{ | ||
|
||
//=============================================================================================================== | ||
// GeneralWorkerThread | ||
//=============================================================================================================== | ||
|
||
//-Constructor-------------------------------------------------------------------- | ||
//Public: | ||
GeneralWorkerThread::GeneralWorkerThread() : | ||
mWorkerCount(0) | ||
{ | ||
/* mThread is the only QObject member of this class. We need to move it to the main thread because | ||
* the manager can be created in any thread since it's done by RAII and UB occurs if a Object (in this case | ||
* the QThread) continues to be used if the thread it belongs to is shutdown. moveToThread() already checks | ||
* if this is the main thread and results in a no-op if so. Also, QThread's public methods are protected | ||
* by a mutex, so it's safe to interact with it from which ever thread is accessing the manager. | ||
*/ | ||
QThread* mainThread = QCoreApplication::instance()->thread(); | ||
if(!mainThread) [[unlikely]] | ||
{ | ||
// It's documented that you're not supposed to use QObjects before QCoreAppliation is created, | ||
// but check explicitly anyway | ||
qCritical("Cannot use QObject's before QCoreApplication is created!"); | ||
} | ||
|
||
mThread.moveToThread(mainThread); | ||
} | ||
|
||
//-Destructor-------------------------------------------------------------------- | ||
//Public: | ||
GeneralWorkerThread::~GeneralWorkerThread() | ||
{ | ||
if(mThread.isRunning()) | ||
stopThread(true); | ||
} | ||
|
||
//-Instance Functions-------------------------------------------------------------------------------------------- | ||
//Private: | ||
void GeneralWorkerThread::startThread() | ||
{ | ||
Q_ASSERT(!mThread.isRunning()); | ||
mThread.start(QThread::LowPriority); // The work here should be on the lighter side | ||
} | ||
|
||
void GeneralWorkerThread::stopThread(bool wait) | ||
{ | ||
Q_ASSERT(mThread.isRunning()); | ||
mThread.quit(); | ||
if(wait) | ||
mThread.wait(); | ||
} | ||
|
||
void GeneralWorkerThread::workerDestroyed() | ||
{ | ||
if(!--mWorkerCount) | ||
stopThread(); | ||
} | ||
|
||
//Public: | ||
void GeneralWorkerThread::moveTo(QObject* object) | ||
{ | ||
if(!mWorkerCount++) | ||
startThread(); | ||
|
||
object->moveToThread(&mThread); | ||
|
||
// Worker management | ||
|
||
/* Have worker killed if it still exists when thread is being shutdown; | ||
* | ||
* QThread docs note that deferred deletions still occur after finished is emitted, so this is possible | ||
* (this use case is explicitly mentioned). | ||
*/ | ||
QObject::connect(&mThread, &QThread::finished, object, &QObject::deleteLater); | ||
QObject::connect(object, &QObject::destroyed, object, []{ GeneralWorkerThread::instance()->workerDestroyed(); }); // Notify of destruction | ||
} | ||
|
||
} | ||
/*! @endcond */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
#ifndef QX_GENERALWORKERTHREAD_H | ||
#define QX_GENERALWORKERTHREAD_H | ||
|
||
// Qt Includes | ||
#include <QThread> | ||
|
||
// Intra-component Includes | ||
#include "qx/core/qx-threadsafesingleton.h" | ||
|
||
/*! @cond */ | ||
namespace Qx | ||
{ | ||
|
||
/* A dedicated thread for Qx worker objects so that we can be sure the thread they run on is never blocked | ||
* for long periods. Automatically starts up when objects are added, and stops when the last one is removed. | ||
* | ||
* Although this is called "GeneralWorkerThread", it's more so its manager. The real thread is created | ||
* by QThread. So, this class can be called anywhere, at anytime; therefore, we make it TSS | ||
*/ | ||
class GeneralWorkerThread : public ThreadSafeSingleton<GeneralWorkerThread> | ||
{ | ||
QX_THREAD_SAFE_SINGLETON(GeneralWorkerThread); | ||
//-Instance Variables------------------------------------------------------------------------------------------------- | ||
private: | ||
QThread mThread; | ||
uint mWorkerCount; | ||
|
||
//-Constructor------------------------------------------------------------------------------------------------- | ||
private: | ||
GeneralWorkerThread(); | ||
|
||
//-Destructor------------------------------------------------------------------------------------------------- | ||
public: | ||
~GeneralWorkerThread(); | ||
|
||
//-Class Functions--------------------------------------------------------------------------------------------- | ||
public: | ||
|
||
|
||
//-Instance Functions-------------------------------------------------------------------------------------------- | ||
private: | ||
void startThread(); | ||
void stopThread(bool wait = false); | ||
void workerDestroyed(); | ||
|
||
public: | ||
void moveTo(QObject* object); | ||
}; | ||
|
||
} | ||
/*! @endcond */ | ||
|
||
#endif // QX_GENERALWORKERTHREAD_H |