diff --git a/src/public/abstractnode.cpp b/src/public/abstractnode.cpp index b0846a57..265145ed 100644 --- a/src/public/abstractnode.cpp +++ b/src/public/abstractnode.cpp @@ -54,14 +54,9 @@ AbstractNode::AbstractNode( QObject *ptr): initThreadId(); - _senderThread = new QThread(); - _senderThread->setObjectName("Sender"); - - _senderThread->start(); - - // This object moving to _senderThread. - _dataSender = new DataSender(_senderThread); - _socketWorker = new AsyncLauncher(_senderThread); + // All sockets and the data sender are created and work in the node worker thread (main thread). + _dataSender = new DataSender(mainThreadID()); + _socketWorker = new AsyncLauncher(mainThreadID()); _tasksheduller = new TaskScheduler(); _apiVersionParser = new APIVersionParser(this); @@ -89,9 +84,6 @@ AbstractNode::AbstractNode( QObject *ptr): AbstractNode::~AbstractNode() { - _senderThread->quit(); - _senderThread->wait(); - for (auto it: std::as_const(_receiveData)) { delete it; } @@ -99,7 +91,6 @@ AbstractNode::~AbstractNode() { _receiveData.clear(); delete _dataSender; - delete _senderThread; delete _socketWorker; delete _tasksheduller; delete _apiVersionParser; @@ -151,6 +142,31 @@ void AbstractNode::stop() { } _connectionsMutex.unlock(); + // Pool workers can be blocked while they wait for a job that was posted + // to the main thread (for example, socket writes executed by the data + // sender). Only this thread can deliver those jobs, so it must keep + // processing events until all workers are finished. Otherwise this + // method would wait for the workers and the workers would wait for this + // thread (deadlock). + const auto deadline = QDeadlineTimer(WAIT_TIME); + while (!deadline.hasExpired()) { + bool hasWork = false; + _workersMutex.lock(); + for (const auto &worker : _workers) { + if (worker && !worker->isFinished()) { + hasWork = true; + break; + } + } + _workersMutex.unlock(); + + if (!hasWork) { + break; + } + + QCoreApplication::processEvents(QEventLoop::AllEvents, 100); + } + _workersMutex.lock(); for (auto it: std::as_const(_workers)) { if (!it->isFinished()) { diff --git a/src/public/abstractnode.h b/src/public/abstractnode.h index c61ae62b..8aa665e1 100644 --- a/src/public/abstractnode.h +++ b/src/public/abstractnode.h @@ -789,7 +789,6 @@ private slots: DataSender * _dataSender = nullptr; AsyncLauncher * _socketWorker = nullptr; - QThread *_senderThread = nullptr; TaskScheduler *_tasksheduller = nullptr; APIVersionParser *_apiVersionParser = nullptr; diff --git a/src/public/async.cpp b/src/public/async.cpp index cecfc4a6..14538981 100644 --- a/src/public/async.cpp +++ b/src/public/async.cpp @@ -5,7 +5,6 @@ * of this license document, but changing it is not allowed. */ -#include "abstractnode.h" #include "async.h" #include @@ -62,9 +61,7 @@ void Async::asyncHandler(Job job, } void Async::threadAnalize(QThread *thread) { - QThread * mainThread = AbstractNode::mainThreadID(); - - debug_assert((mainThread != thread) && thread, "You try create async object into main thread"); + debug_assert(thread, "Async object must be initialized with a valid work thread"); } bool Async::waitFor(bool *condition, int timeout, bool freaze) const { diff --git a/src/public/async.h b/src/public/async.h index 9553f16a..7566b92d 100644 --- a/src/public/async.h +++ b/src/public/async.h @@ -48,7 +48,8 @@ class HEARTSHARED_EXPORT Async: public QObject { * @brief Async This is default constructor of the async object. * @param thread This is work thread of the async object. * @param ptr This is pointer to qtparent of this object. - * @note @a thread must be different of the main thread. + * @note @a thread must be a valid thread. It is allowed to use the node worker (main) thread: + * in this case all jobs are executed directly in that thread. */ Async(QThread* thread);