Destroying thread and exiting loop - c++

I'm creating a thread like this:
main.cpp
QThread acceptorThread;
acceptorObject acceptorobject;
acceptorobject.setupConnections(acceptorThread, simulation);
acceptorobject.moveToThread(&acceptorThread);
acceptorObject.cpp
void acceptorObject::setupConnections(QThread& thread, Simulation * simulation)
{
QObject::connect(&thread, SIGNAL(started()), this, SLOT(acceptNewClients()));
}
acceptNewClients() method works in infinite loop. At this point if I close my program I would get an error:
QThread destroyed while thread is still running
I looked through similar problems at stack and one guy said that I need to break the loop before finishing the thread in order to get rid of this bug. He also suggested to use a flag in infinite loop and emit a signal in destructor that will change the flag and eventually break the loop. It KINDA worked when I did something like this:
QObject::connect(&thread, SIGNAL(started()), this, SLOT(acceptNewClients()));
QObject::connect(this, SIGNAL(finishThread(bool)), this, SLOT(acceptNewClients(bool)));
And then emited finishThread(true) signal from destructor so I directly changed the flag. Of course I changed slot signature as well so it won't run in new thread anymore.
destructor code:
emit finishThread(true);
this->thread()->quit();
if(!this->thread()->wait(3000))
{
this->thread()->terminate();
this->thread()->wait();
}
How can I make this work?
What I've tried so far:
Adding a new slot that will change the flag. Result: when I close program the window dissapears but the proccess is still running. I think that destructor destroys the object before its emited signal is proccessed .
Making bool argument in acceptNewClients() slot a default one. Result: it overloads the funtion so one is run in different thread and the second one tries to change the flag which obviously doesn't work because they are completely different functions.

Solution:
connect(this, SIGNAL(finishThread()), &thread, SLOT(quit()));
connect(this, SIGNAL(finishThread()), this, SLOT(deleteLater()));
It was pointless to change slot function signature in this case.
In deconstructor I simply emit finishThread() signal, nothing more.

One way is instead of doing a while(true) in acceptNewClients you instead do
void acceptorObject::acceptNewClients(){
// do accept new client
QMetaObject::invokeMethod(this, "acceptNewClients", Qt::QueuedConnection);
}
In essence making the loop external.
The other option is to make everything use signals, QTcpServer (which I think you are using) has a newConnection signal you can connect to. Instead of using waitForNewConnection.

Related

QThread: slot quit() is never invoked and hence the thread wait() is forever

I have the exact same problem as described QThread won't stop / does not process a signal but with a twist. I cannot get it to work even with QCoreApplication::processEvents() to my while loop. I followed this blog post and ended up like as follows:
MediaController.cpp
void MediaController::buttonPlayClicked(bool checked)
{
if (checked)
{
m_loopThread = new QThread;
m_playPauseworker = new PlayPauseWorker;
m_playPauseworker->moveToThread(m_loopThread);
connect(m_playPauseworker, &PlayPauseWorker::dataReady, this, &MediaController::onDataReady);
connect(m_loopThread, &QThread::started, m_playPauseworker, &PlayPauseWorker::process);
connect(m_playPauseworker, &PlayPauseWorker::finished, m_loopThread, &QThread::quit); // <-- never works
connect(m_playPauseworker, &PlayPauseWorker::finished, m_playPauseworker, &PlayPauseWorker::deleteLater);
connect(m_loopThread, &QThread::finished, m_loopThread, &QThread::deleteLater);
m_loopThread->start();
}
else
{
m_loopThread->requestInterruption();
}
}
The above slot is called every time play/pause checkable button is clicked. Thread and worker are created on the main thread.
PlayPauseWorker.cpp
void PlayPauseWorker::process()
{
while (!QThread::currentThread()->isInterruptionRequested())
{
// heavy computations
emit dataReady(std::tuple<QImage, QImage, QImage>>); // <-- works!
QCoreApplication::processEvents(); // <-- doesn't help with quit()
}
emit finished(); // <-- emits the signal but quit() not called
}
On further processing, when i access wait() to see if my thread has exited, it never returns.
In addition to quit() slot never called, i noticed my GUI becomes very choppy when the thread is running. I sometimes can/cannot click on other buttons or play with UI. I went through a lot of SO posts but couldn't figure out a way to cleanly exit the thread whenever i need to. Not sure where am i going wrong.
After trying out a lot of suggestions i still couldn't figure out why emit finished() doesn't quit the thread. So, as a last resort, i used this->thread->quit() to achieve the same.
But thanks to all the commenters here, i narrowed down on laggy/choppy gui issue.
My emit data(std::tuple<QImage, QImage, QImage>>) was setting pixmap on QGraphicsScene on a loop without removing the already set pixmap on the scene leading to huge memory leak and ultimately crash.

QTcpSocket in QThread will commitTransaction but when Write is called "Cannot create children for a parent that is in a different thread."

Disclaimer: I am relatively new to Qt and any type of programming that revolves around Threads and Networking. I have also adopted a lot of code from Qt Examples, API, and other online examples.
All code can be found on GitHub. This code is relatively as simple as it can get minus striping out GUI. I figure supplying it this way would help as well versus just pasting the code below.
I want to use and believe I need to use Threads as I need multiple clients send a request to the server, the server run some SQL code, then spit out the results back to the client (basically deriving a MySQL Server, but specific to what I am doing). Right now though, I am just working on learning the workings of it all.
With all that being said, as the Title states.. My client can connect to the server, the server sets up the thread, and will receive data (a String) through the readReady. After the data is read in, for right now I am just trying to echo it back to the client. It will do this, but only once. Then it spits out:
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNativeSocketEngine(0x266cca92ea0), parent's thread is serverThread(0x266cca9ed60), current thread is QThread(0x266cac772e0)
I cannot send any further data to the server unless I have the client reconnect, then after the data is sent, it will do its job but then spit out the same error and cease functioning. I have tried quite a bit of different things, but cannot seem to fix the issue. I even tried setting up a SIGNAL/SLOT for this as suggested in API:
It is important to remember that a QThread instance lives in the old thread that instantiated it, not in the new thread that calls run(). This means that all of QThread's queued slots will execute in the old thread. Thus, a developer who wishes to invoke slots in the new thread must use the worker-object approach; new slots should not be implemented directly into a subclassed QThread.
Anyway, any help would be greatly appreciated! My Code is below..
Server
ServerThread.cpp
// Project
#include "ServerDialog.h"
#include "ServerThread.h"
ServerThread::ServerThread(qintptr _socketDiscriptor, QObject *parent /*= 0*/)
: QThread(parent)
{
socketDiscriptor = _socketDiscriptor;
}
void ServerThread::run()
{
emit threadStarted(socketDiscriptor);
// Start Thread
clientSocket = new QTcpSocket;
// Set SocketDisc
if (!clientSocket->setSocketDescriptor(socketDiscriptor))
{
emit error(clientSocket->error());
return;
}
// Connect Socket and Signal
connect(clientSocket, SIGNAL(readyRead()), this, SLOT(readyRead()));
connect(clientSocket, SIGNAL(disconnected()), this, SLOT(disconnected()));
//// Loop Thread to Stay Alive for Signals and Slots
exec();
}
void ServerThread::readyRead()
{
QDataStream in(clientSocket);
in.setVersion(QDataStream::Qt_5_7);
in.startTransaction();
QString dataReceived;
in >> dataReceived;
if (!in.commitTransaction())
{
emit readyReadError(socketDiscriptor);
return;
}
emit readyReadMessage(socketDiscriptor, dataReceived);
echoData(dataReceived);
}
void ServerThread::disconnected()
{
emit threadStopped(socketDiscriptor);
clientSocket->disconnect();
clientSocket->deleteLater();
this->exit(0);
}
void ServerThread::echoData(QString &data)
{
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_5_7);
out << data;
clientSocket->write(block);
}
So in ServerThread.cpp when echoData is called, that is when the error shows up and the Socket ceases functioning.
Any and all help will be appreciated. I know there are a few other posts regarding "Cannot create children for..." in regards to Threads. But I did not find any of them helpful. The one thing that I did find interesting but did not understand was maybe using moveToThread() but a lot of mixed comments on that.
I learn best through code examples along with explanation versus just an explanation or pointer to API. Thank you!
Most of Qt network functions are asynchronous; they do not block the calling thread. There is no need to mess up with threads if you are using QTcpSockets. In fact, creating a thread for every socket is an overkill, since that thread will spend most of its time just waiting for some network operation to finish. Here is how I would implement a single-threaded echo server in Qt:
#include <QtNetwork>
#include <QtCore>
//separate class for the protocol's implementation
class EchoSocket : public QTcpSocket{
Q_OBJECT
public:
explicit EchoSocket(QObject* parent=nullptr):QTcpSocket(parent){
connect(this, &EchoSocket::readyRead, this, &EchoSocket::EchoBack);
connect(this, &EchoSocket::disconnected, this, &EchoSocket::deleteLater);
}
~EchoSocket() = default;
Q_SLOT void EchoBack(){
QByteArray receivedByteArray= readAll();
write(receivedByteArray);
disconnectFromHost();
}
};
class EchoServer : public QTcpServer{
public:
explicit EchoServer(QObject* parent= nullptr):QTcpServer(parent){}
~EchoServer() = default;
//override incomingConnection() and nextPendingConnection()
//to make them deal with EchoSockets instead of QTcpSockets
void incomingConnection(qintptr socketDescriptor){
EchoSocket* socket= new EchoSocket(this);
socket->setSocketDescriptor(socketDescriptor);
addPendingConnection(qobject_cast<QTcpSocket*>(socket));
}
EchoSocket* nextPendingConnection(){
QTcpSocket* ts= QTcpServer::nextPendingConnection();
return qobject_cast<EchoSocket*>(ts);
}
};
int main(int argc, char* argv[]){
QCoreApplication a(argc, argv);
EchoServer echoServer;
echoServer.listen(QHostAddress::Any, 9999);
QObject::connect(&echoServer, &EchoServer::newConnection, [&](){
EchoSocket* socket= echoServer.nextPendingConnection();
qDebug() << "Got new connection from: " << socket->peerAddress().toString();
});
return a.exec();
}
#include "main.moc"
Notes:
This server has the ability to handle more than one client at the same time, since there is no blocking. The thread will just respond to the event that happens with the appropriate action; So, if that event was a new connection, it will create a new EchoSocket object to handle it and prints a statement out to qDebug(), and if that event was receiving something on a previously created socket, the same thread will echo received data back and close the connection. It will never block on a single connection waiting for data to arrive nor it will block waiting for a new connection to arrive.
Since you mention using some SQL queries in response for some connections later in your project. Please avoid threading since an SQL database connection in Qt can be used only from the thread that created it, see docs here. So, You'll have to either create a new database connection for each thread (and thus for each connection) in your application (and this is beyond just overkill), or switch later to a single threaded design.
In this section, I am explaining why threading does not work for you the way you are doing it:
You should not be declaring slots in your QThread subclass, Instead, use worker QObjects and move them to QThreads as needed.
The quote you have provided in your question is the exact explanation for why you get this warning. The ServerThread instance you create will be living in the main thread (or whatever thread that created it). Now let's consider this line from your code:
connect(clientSocket, SIGNAL(readyRead()), this, SLOT(readyRead()));
The signal readyRead() will be emitted from the current ServerThread instance (since the clientSocket object that emits it lives there), However, the receiver object is the current ServerThread instance, But that lives in the main thread. Here is what the documentation says:
If the receiver lives in the thread that emits the signal, Qt::DirectConnection is used. Otherwise, Qt::QueuedConnection is used.
Now, the main point of Qt::QueuedConnection is executing the slot in the receiver object's thread. This means that, your slots ServerThread::readyRead() and ServerThread::disconnected will get executed in the main thread. This is most likely not what you meant to do, since you'll end up accessing clientSocket from the main thread. After that, any call on clientSocket that results in child QObjects being created will result in the warning you get (you can see that QTcpSocket::write() does this here).
Mixed comments of movetothread are linked mostly to usage of it to move thread object to itself.
The quote hints that the members of QThread aren't designed to be called from worker. Strictly proper way to call signal would be by using worker object model, that was shown in Qt examples and explained a few times on QT-related blogs:
class Worker : public QObject
{
Q_OBJECT
private slots:
void onTimeout()
{
qDebug()<<"Worker::onTimeout get called from?: "<<QThread::currentThreadId();
}
};
class Thread : public QThread
{
Q_OBJECT
private:
void run()
{
qDebug()<<"From work thread: "<<currentThreadId();
QTimer timer;
Worker worker;
connect(&timer, SIGNAL(timeout()), &worker, SLOT(onTimeout()));
timer.start(1000);
exec();
}
};
worker constructed inside run() is "property" of the thread it created, so figuratively speaking, it is slaved to its context. The same effect maybe achieved if you create worker in other thread, then move it to this thread before connection was made. When you connect signal to slot of the QThread itself, you connect child thread to thread it was created by.
Use of
connect(&timer, SIGNAL(timeout()), this, SLOT(onTimeout()), Qt::DirectConnection);
or creating connection from your thread sometimes seems to achieve proper result, but not in this case, where you try use objects constructed in different threads together. Calling moveToThread(this) in constructor is a thing not recommended to do.

QProcess unknown error

I got strange problem. QProcess just not working!
And error is unknown.
I got global var in header
QProcess *importModule;
An I got this function ( I tried both start and startDetached methods btw )
void App::openImport(){
importModule = new QProcess();
importModule->setWorkingDirectory(":\\Resources");
importModule->startDetached("importdb_module.exe");
QMessageBox::information(0,"",importModule->errorString());
}
It jsut outputs that error is unknown. Also it wont start other exes like
void App::openImport(){
importModule = new QProcess();
importModule->setWorkingDirectory("C:\\Program Files\\TortoiseHg");
importModule->startDetached("hg.exe");
QMessageBox::information(0,"",importModule->errorString());
}
What I've done wrong?
And is there other ways to run some .exe from my programm?
Or maybe .bat files(which runs exes)? (Tried with QProcess too, not working)
startDetached() is a static method and doesn't operate on importModule at all.
It starts a process and then stops caring. Thus the error()/errorState() in importModule has nothing to do with the startDetached() call. What you want is start().
However, as QProcess is asynchronous, nothing will have happened yet immediately after start() returns. You must connect to the started(), error() and finished() signals to learn about the result.
connect(importModule, SIGNAL(started()), this, SLOT(importModuleStarted()));
connect(importModule, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(importModuleFinished(int, QProcess::ExitStatus)));
CONNECT(importModule, SIGNAL(error(QProcess::ProcessError)), this, SLOT(importModuleError(QProcess::ProcessError)));
importModule->start(QStringLiteral("importdb_module"), QStringList());
Alternatively you can use the blocking wait functions:
importModule->start(QStringLiteral("importdb_module"), QStringList());
importModule->waitForStarted(); // waits until starting is completed
importModule->waitForFinished(); // waits until the process is finished
However, I strongly advise against using them in the main thread, as they block the UI then.

Want to put a method into a QThread

How to add a method within the class to a thread to execute?
I do not want to put "Pup" into a seperate class that inherits QThread as this is just an abstraction of some Legacy code I am working on.
void Dog::Pup()
{
printf("pup");
}
void Dog::Init()
{
QThread *dogThread = new QThread();
Pup->moveToThread(dogThread); //this is all wrong
Pup->connect(dogThread, ?, Pup, SLOT(Pup), ?)
dogThread.start();
}
Try this:
void Dog::Init()
{
QThread *dogThread = new QThread;
connect(dogThread, SIGNAL(started()), this, SLOT(Pup()), Qt::DirectConnection);
dogThread->start();
}
It basically creates a new QThread named dogThread and connects it's started() signal to the method you want to run inside the thread (Dog::Pup() which must be a slot).
When you use a Qt::QueuedConnection the slot would be executed in the receiver's thread, but when you use Qt::DirectConnection the slot will be invoked immediately, and because started() is emitted from the dogThread, the slot will also be called from the dogThread. You find more information about the connection types here: Qt::ConnectionType.
if you want to run a single function in another thread, you should check out the methods in the QtConcurrent namespace.
Read the Detailed description in the page http://doc.qt.io/qt-5/qthread.html

Multi-threading in Qt problematic?

I have been learning Qt for a while and a few days ago I decided to go on multi-threading by QThread. I have been following this person. Since he says that subclassing QThread is not the appropriate way but by using QObject is. I am following his method. But he has created another class which inherits from QObject. I decided to make a few changes:
class myclass
{
private:
dowork();
private slots:
slota();
slotb();
slotc();
}
myclass::dowork()
{
QThread lett;
QThread latt;
QThread pltt;
QObject lethread;
connect(&lett, SIGNAL(started()), this, SLOT(slota()));
lethread.moveToThread(&lett);
QObject lathread;
connect(&latt, SIGNAL(started()), this, SLOT(slotb()));
lathread.moveToThread(&latt);
QObject plthread;
connect(&pltt, SIGNAL(started()), this, SLOT(slotc()));
plthread.moveToThread(&pltt);
lett.start();
latt.start();
pltt.start();/*
lett.wait();
latt.wait();
pltt.wait();*/
while(lett.isRunning())
{
//qDebug() << "Still Running!";
}
lett.quit();
}
If I run the program it keeps running while loop infinitely! It doesn't come out of that at all.
I used qdebug inside the implementation of the 3 slots to check whether it is entering them or not, and surprisingly none of the slots gets called. Why is that so?
If I remove the comments for .wait then the program pauses.
What is wrong in this method? I want to avoid that extra class as my program is very small.
while(lett.isRunning())
{
//qDebug() << "Still Running!";
}
lett.quit();
Terribly wrong. The current thread is busy waiting and will be eating all the time. But this is not your problem. Your problem is certainly that the main event loop has probably not started yet, ie you didn't do QApplication.exec() yet.
Qt uses events to start threads, and when you do use movetoThread, start, specific events are queued in the current thread (ie the thread executing these methods). If the main event loop has already started, then will be processed as soon as they can. But in your case I bet that you main function is :
int main(){
QApplication app();
myclass onlyclassIwanttomake;
onlyclassIwanttomake.dowork();
app.exec(); <----HERE!!!
}
The thread will be started when the main thread executes app.exec();. When you are busy waiting, you are preventing the main thread to process the events required to start your
events.
EDIT: Well, another issue is that
lett.start();
latt.start();
pltt.start();
start 3 threads which are started, and stay idle forever. They are not doing anything, but they are running (even if you remove your loop).
This is a entry written about Qt threading. Please take the time to read it.