[related to this question]
I wrote this piece of code to understand how qt signals and slots work. I need someone to explain the behaviour, and to tell me if I'm right about my own conclusions.
My program:
connectionhandler.h
#ifndef CONNECTIONHANDLER_H
#define CONNECTIONHANDLER_H
#include <QTcpServer>
class ConnectionHandler : public QObject
{
Q_OBJECT
public:
ConnectionHandler();
public slots:
void newConn();
private:
QTcpServer *server;
};
#endif // CONNECTIONHANDLER_H
connectionhandler.cpp
#include "connectionhandler.h"
#include <QTextStream>
ConnectionHandler::ConnectionHandler() {
server = new QTcpServer;
server->listen(QHostAddress::LocalHost, 8080);
QObject::connect(server, SIGNAL(newConnection()),this, SLOT(newConn()));
}
void ConnectionHandler::newConn() {
QTextStream out(stdout);
out << "new kanneksan!\n";
out.flush();
}
main.cpp
#include <QCoreApplication>
#include "connectionhandler.h"
int main(int argc, char* argv[]) {
QCoreApplication app(argc,argv);
ConnectionHandler handler;
return app.exec();
}
Now, running this program sends it into an infinite loop looking for new connections.
Observation: if I don't call app.exec(), the program returns immediately (as it should).
Question: why?
Question: if I had connected the slot as a queued connection, when would the slot invocation be performed?
Question: if app.exec() is an infinite loop of sorts, how does the newConnection() signal ever get emitted?
Big Question: Is their any "second thread" involved here? (I expect a no, and a stunningly elegant explanation :) )
Thanks,
jrh
PS: who else has this nested parenthesis syndrome? like "(.. :))" or "(.. (..))"?
If you don't call app.exec() then the program hits the end of your main() and ends. (Why? There's no more code to execute!)
app.exec() is an infinite loop of the following style:
do
{
get event from system
handle event
}
while (true);
If you use a queued connection, then the event is added to your event queue, and it will be performed at some point in the future during the app.exec() loop.
There is no second thread in your program. Events are delivered asynchronously by the OS, which is why it appears that there's something else going on. There is, but not in your program.
app.exec() enters the main event loop and waits until exit() is called.
update:
The main event loop and the glue code generated by qmake take care of transferring the event message from the QTcpServer to your ConnectionHandler.
If you'd use queued connections the actual connection to the QTcpServers slot would be delayed until the main event loop delivers the connection request.
When you say it enters an infinite loop, you mean it crashes the program?
Because listen() will become part of the main application event loop the way you have it set up, which runs until you exit the program. I'm not sure what the problem is. There should be no trouble of your signal being emitted in the main application event loop (exec()) whenever one is encountered.
If you like, you could have your ConnectionHandler class extend QThread and run listen() in it's own thread, apart from the main application loop.
Related
I am working on a Qt-C++ based front-end app for a Raspberry Pi powered robot. I am using Qt version 5.9 along with libraries QSerialPort and Pigpio. In my app, when I give the run command for a command sequence to the robot, my Raspberry Pi starts a serial communication with a microcontroller in which it sends some message and then waits to receive a response. This sending and waiting causes the Mainwindow thread to freeze up. I am trying to build in a emergency stop functionality, which would stop the command execution in the middle of the run process.
Towards that effort, I tried to push my serial communication part to a separate thread(QThread). It didn't work out. Now I am trying to build the emergency stop part into a QDialog box that opens up when I give the run command, which contains a emergency stop QPushbutton. The Dialog box is being run in non-modal form. But in my current code, when I give the run command, a dialog box does open up, but the dialog box is completely blank and then closes up when the run command ends(which is intentional). I'll share some screenshots of the appearance.
Can you suggest where I might be going wrong? Or is there a better approach to this issue? Any criticism and suggestions are welcome!
Thanks!
One shouldn't block the main thread in the Qt. Everytime you call the blocking function, your GUI freezes, as well as Dialog boxes.
One solution is to use signal/slots. They blend really well into Qt. But doing a complicated request/response logic would require a huge state machine usually prone to errors.
Sometimes it is better to leave this code blocking, create a plain chain of request/response code, and put it in another non-GUI thread. Then use the signal to notify the main thread about the job result.
In order to stop the execution it is possible to use an atomic and check it between blocking steps. The biggest time delay before exiting the working function is the biggest delay of the single blocking function. You should carefully tune the timeouts. Or you can write your own function, which emulates timeout and a stop condition. It should check if incoming data is available in an infinite loop and check fro stop condition on each iteration, which must be a timeout AND a stop condition variable.
// pseudocode here
while (true) {
if (stopCondition) return; // check for emergency condition
it (currentTime - startTime > timeout) return;
if (serial->dataReady()) break;
}
auto data = serial->getData();
If a step can block forever, then this method can't be used.
There is an example with QtConcurrent framework, which demonstrates the use of QFuture and the work of a function in a separate thread without blocking the main thread. You can put all your communication logic inside it.
The code is example only!
#ifndef WORKERCLASS_H
#define WORKERCLASS_H
#include <QObject>
#include <QtConcurrent/QtConcurrent>
#include <QFuture>
class WorkerClass : public QObject
{
Q_OBJECT
public:
explicit WorkerClass(QObject *parent = nullptr) : QObject(parent) {
connect(&futureWatcher, &QFutureWatcher<void>::finished, [this] () {
emit workFinsihed();
});
}
void startWork(int value) {
atomic = 0;
future = QtConcurrent::run(this, &WorkerClass::workFunction, value);
futureWatcher.setFuture(future);
}
void stopWork() {
atomic = 1;
}
private:
QFuture<void> future;
QFutureWatcher<void> futureWatcher;
void workFunction(int value) {
for (int i = 0; i < value; ++i) {
if (atomic) return;
}
return;
};
QAtomicInt atomic{0};
signals:
void workFinsihed();
};
#endif // WORKERCLASS_H
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.
I have a multithreaded application written in C++ with Qt. Currently, my application works by having a QThread instance (I have NOT subclassed QThread) which uses the default run() implementation that just calls QThread's exec() method, which provides an event dispatch loop.
I call moveToThread on certain QObject subclasses which actually perform the work I want done in a separate thread. I tell these objects to do work using Qt's signals/slots mechanism. I stop the thread gracefully by informing my worker objects to stop their work, and then calling quit() and wait() on my thread. This all works very nicely.
However, I now want to implement the following scenario:
The user clicks e.g. the "X" button on my application, because they want to close it.
I don't want any new work to be started, so I pause the event dispatch thread. If the current event being dispatched continues running, that's fine.
I prompt the user, allowing them to either a) discard all remaining jobs and exit (using quit() andwait()` - this already works), or b) don't exit the application, but instead continue working (resume the thread).
My problem is that QThread doesn't seem to have a pause() method. I've seen various examples online which add one (like the answers to this question). The problem is that these examples depend on having a custom run() implementation, and implementing pause there. Since I'm relying on QThread's event dispatch loop, these solutions won't work. I've considered doing something like reimplementing exec() or creating my own subclass of QAbstractEventDispatcher, but these solutions seem like a whole lot of work to get simple pause / resume functionality.
What's the easiest way to pause QThread's event dispatch loop (preventing it from dispatching any new events, but letting the current event continue)?
I tried out the method suggested in the comments, but it took a bit of screwing around to get it to work totally correctly, so here's what I ended up with:
I subclassed QThread to add two new methods: pause and resume. There were a few things that needed to be dealt with delicately:
Calling start() while the thread is still running does nothing. Since resume() might be called before the thread's existing job stops running, we need to do the actual resume in a slot connected to the thread's finished() signal.
The finished() signal may be emitted just before the thread actually stops. Because of this, we need to call wait() in our slot before calling start().
If resume() is called after the thread is already stopped, simply setting state variables won't work, because finished() will never be emitted. Because of this, we need to deal with that case by having non-signal-related resume code in the resume() method as well.
Here's the final product.
pausablethread.h:
#ifndef INCLUDE_PAUSABLE_THREAD_H
#define INCLUDE_PAUSABLE_THREAD_H
#include <QThread>
class QMutex;
class PausableThread : public QThread
{
Q_OBJECT
public:
PausableThread(QObject *parent = 0);
virtual ~PausableThread();
void pause();
void resume();
private:
QMutex *controlMutex;
bool paused;
bool resumeScheduled;
private Q_SLOTS:
void doResume();
};
#endif
pausablethread.cpp:
#include "pausablethread.h"
#include <QMutex>
#include <QMutexLocker>
PausableThread::PausableThread(QObject *parent)
: QThread(parent), paused(false), resumeScheduled(false)
{
controlMutex = new QMutex(QMutex::NonRecursive);
QObject::connect(this, SIGNAL(finished()),
this, SLOT(doResume()));
}
PausableThread::~PausableThread()
{
delete controlMutex;
}
void PausableThread::pause()
{
QMutexLocker locker(controlMutex);
if(paused)
return;
paused = true;
quit();
}
void PausableThread::resume()
{
QMutexLocker locker(controlMutex);
if(!paused)
return;
if(resumeScheduled)
return;
if(isFinished())
{
start();
paused = false;
resumeScheduled = false;
}
else
{
resumeScheduled = true;
}
}
void PausableThread::doResume()
{ /* SLOT */
QMutexLocker locker(controlMutex);
if(!resumeScheduled)
return;
paused = false;
resumeScheduled = false;
wait();
start();
}
This seems to work, mostly. I believe there are some potential race conditions if the thread happens to finish or start at the same time execution is inside resume() or doResume() in a different thread. It's not exactly clear to me how to solve this.
I tried something like overriding the superclass's start() slot with the following:
void start(Priority priority)
{
QMutexLocker locker(controlMutex);
QThread::start(priority);
}
The problem with this is that start() never actually returns until the thread finishes, so it never releases its lock on the mutex. Thus, when doResume() tries to acquire a lock, a deadlock is encountered, and the thread isn't successfully resumed.
I think what is really needed is a mutex which is exclusively locked any time the thread's running state is changed, but it isn't clear to me how to implement this.
Regardless, the window for this race to occur is very small,and this works "well enough" to answer my question. Thanks to #Lol4t0 for the suggestion!
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.
In my application I have the following code in a dialog:
connect(drive, SIGNAL(FileProgressChanged(Progress)), SLOT(OnFileProgressChanged(Progress)));
QtConcurrent::run(this, &ProgressDialog::PerformOperation, Operation, *Path, OutPath, drive);
The PerformOperation function eventually calls to a function in drive which emits the signal FileProgressChanged, and my OnFileProgressChanged function is as follows:
void ProgressDialog::OnFileProgressChanged(Progress p)
{
if (ui->progressCurrent->maximum() != p.Maximium)
ui->progressCurrent->setMaximum(p.Maximium);
ui->progressCurrent->setValue(p.Current);
if (ui->groupBoxCurrent->title().toStdString() != p.FilePath)
ui->groupBoxCurrent->setTitle(QString::fromStdString(p.FilePath));
}
I was doing some reading and saw that QFuture and QFutureWatcher support monitoring progress values (which would work great in this situation!), but those cannot be used in conjunction with QtConcurrent::run.
How would I go about connecting the signal that gets moved emitted on the separate thread to the slot on my main thread so I can monitor the progress of the function called on the emitter thread?
*Edit -- * I actually found an error with my code, but it doesn't seem to have an affect. I forgot to add this as an argument after the signal
connect(drive, SIGNAL(FileProgressChanged(Progress)), this, SLOT(OnFileProgressChanged(Progress)));
Try using connect() with QueuedConnection, like:
connect(drive, SIGNAL(FileProgressChanged(Progress)), this, SLOT(OnFileProgressChanged(Progress)), Qt::QueuedConnection);
The connection should already be queued by default (since the emitter and receiver are in different threads), but this just makes it more explicit.
EDIT: The problem was that the Progress type wasn't registered with Qt's meta-object system. Adding qRegisterMetaType<Progress>("Progress"); fixed the problem.
It appears as though the problem isn't with the cross-thread signal/slot, but instead with the parameter Progress. This question's answer goes into further detail, but the solution was found by doing the following in the header file in which Progress was declared:
struct Progress
{
int Current;
int Maximium;
std::string FilePath;
std::string FolderPath;
int TotalMinimum;
int TotalMaximum;
};
Q_DECLARE_METATYPE(Progress)
And in my form class:
qRegisterMetaType<Progress>();
connect(Drive, SIGNAL(FileProgressChanged(const Progress&)), this, SLOT(OnFileProgressChanged(const Progress&)), Qt::QueuedConnection);
Changing Progress to const Progress& most likely isn't needed but I left it while testing.