Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 28 additions & 12 deletions src/public/abstractnode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -89,17 +84,13 @@ AbstractNode::AbstractNode( QObject *ptr):

AbstractNode::~AbstractNode() {

_senderThread->quit();
_senderThread->wait();

for (auto it: std::as_const(_receiveData)) {
delete it;
}

_receiveData.clear();

delete _dataSender;
delete _senderThread;
delete _socketWorker;
delete _tasksheduller;
delete _apiVersionParser;
Expand Down Expand Up @@ -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()) {
Expand Down
1 change: 0 additions & 1 deletion src/public/abstractnode.h
Original file line number Diff line number Diff line change
Expand Up @@ -789,7 +789,6 @@ private slots:

DataSender * _dataSender = nullptr;
AsyncLauncher * _socketWorker = nullptr;
QThread *_senderThread = nullptr;
TaskScheduler *_tasksheduller = nullptr;
APIVersionParser *_apiVersionParser = nullptr;

Expand Down
5 changes: 1 addition & 4 deletions src/public/async.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
* of this license document, but changing it is not allowed.
*/

#include "abstractnode.h"
#include "async.h"

#include <QCoreApplication>
Expand Down Expand Up @@ -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 {
Expand Down
3 changes: 2 additions & 1 deletion src/public/async.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
Loading