I want to get the stderr of a QProcess (ideally as a QIODevice), but I can't figure out how. Another thread is reading from stdout using the methods QProcess inherits from QIODevice, so QProcess::MergedChannels and QProcess::setReadChannel(...) are out of the question. QProcess::readAllStandardError() is also not ideal.
You have to connect some slot to readyReadStandardError() signal of QProcess to read data by QProcess::readAllStandardError() and be store it for concatenation, in addition to finished() signal to make concluding calls, similar to how you would do that for standard output.
connect(&process, SIGNAL(readyReadStandardError()), this, SLOT(readErrData()));
connect(&process, SIGNAL(finished(int , QProcess::ExitStatus)),
this, SLOT(finalizeProcessTask(int , QProcess::ExitStatus)));
Related
I am working on Qt application. There I would like to have worker thread doing some activities in background and I would like main thread to control it, restarting worker thread if it dies for some reason.
I have seen finished() signal emitted by the thread so I guess I could connect slot to it.
Is that the recommended way? If not, how could I achieve that?
If I use finished() signal how can I know difference between normal termination and error?
Thanks and regards
If you want to know whether you had an error or you had the process finished, simply create two signals, not one, and two slots, not one.
In the Qt documentation you have an example there, with a connection to handle the result:
connect(workerThread, &WorkerThread::resultReady, this, &MyObject::handleResults);
you're here connecting the signal resultReady with whatever method that handles the result. You create another one exactly like this, but with an error signal, and an error handler.
connect(workerThread, &WorkerThread::errorThrown, this, &MyObject::handleErrors);
Of course, another option is to simply pass a parameter with your signals/slots. It's a function call, and if you put some enum with that for the status or some int, that'll do.
I'm pretty new to Qt and programming and are facing a problem I can't find a solution for.
I want to read some information from an online XML file and send it to my main program.
To do so, I created a class XMLParser and added the following to the constructor:
XMLParser::XMLParser(QString searchstring)
{
QNetworkAccessManager *manager2 = new QNetworkAccessManager(this);
reply = manager2->get(QNetworkRequest(QUrl("http://www.boardgamegeek.com/xmlapi/search?search="+searchstring)));
XMLParser::connect(reply, SIGNAL(finished()),
this, SLOT(fileIsReady()) );
}
and fileIsReady fills a QMap and stores it as a private class member.
In my second class, I call
XMLParser *xmlpars = new XMLParser(input_gamename->text());
QMap<QString, int> searchResults = xmlpars->getSearchList();
and getSearchList is a simple getter function.
The problem is, that getSearchList is executed before fileIsReady finished reading the XML file and returns an empty map.
From what I understand, the constructor should not be finished until fileIsReady() finished its work. And thus, getSearchList() shouldn't be called early.
My two questions:
Why does my programm progresses while the function didn't finish reading.
How can I make the second call "getSearchList" wait?
Thanks a lot in advance!
First, you need to understand the fundamental concept of signals and slots.
After you make a connection, the slot will get called every time the signal is emitted.
The connect() functions returns after connecting the signal to the slot. It doesn't wait for the signal to be emitted.
In your XMLParser constructor, your connect() function registers this: "When the finished() signal is emitted, run the fileIsReady() function".
Now, to answer your questions.
Why does my programm progresses while the function didn't finish reading.
Because in your constructor code, you asked the constructor to finish after you connect the signal to the slot. You did not ask it to wait for the download to finish.
And then, you call getSearchList() without waiting for the finished() signal. So, getSearchList() gets called before fileIsReady().
How can I make the second call "getSearchList" wait?
Like MrEricSir said, you shouldn't ask it to wait! (Think about it: What happens if you lose internet connection and can't finish downloading the file? The answer is, your program will freeze because it will wait forever. That's bad.)
Don't call getSearchList() immediately after constructing XMLParser. Instead, make XMLParser emit a "finishedParsing()" signal when it finishes parsing the XML file. Then, make another signal-slot connection: Connect the finishedParsing() signal to a slot that calls getSearchList().
So, I found a solution using QEventLoop. But as far as I read, this isn't recommendend.
Are there any other solutions? And why is using QEventLoop bad habit (That's what I read from other answers here StackOverflow).
XMLParser::XMLParser(QString searchstring)
{
QNetworkAccessManager *manager2 = new QNetworkAccessManager(this);
reply = manager2->get(QNetworkRequest(QUrl("http://www.boardgamegeek.com/xmlapi/search?search="+searchstring)));
QEventLoop loop;
XMLParser::connect(reply, SIGNAL(finished()),
this, SLOT(fileIsReady()) );
XMLParser::connect(this, SIGNAL(finishedReading()),
&loop, SLOT(quit()));
loop.exec();
}
How can I make the second call getSearchList wait?
You don't! Instead, just move any code that expect the XML file to be downloaded into the fileIsReady() slot that you've already defined. That way your program won't lock up while it's waiting for the download to complete (which is the entire point of asynchronous programming.)
problem
i'm currently putting FUSE together with qt5. there is no bridge between Qt and FUSE yet, both the FUSE main thread (which is spawning the other working FUSE threads) and the QCoreApplication are simply running side by side.
but i want to be able to send and receive data between a QObject based object and the pthread's Read(..) function shown in [0] using Qt's SIGNALS and SLOTS.
question
now i want to alter the Read(..) function from [0] to retrieve data using Qt's SIGNALS and SLOTS from a QObject based class. sending a signal from a pthread works but without an explicit QEventLoop i can't receive the reply. therefore i was looking at the code from [1] which is excellent in design but i didn't get it working yet.
pseudo code (taken from [1]):
QNetworkAccessManager qnam;
QNetworkReply *reply = qnam.get(QNetworkRequest(QUrl(...)));
QEventLoop loop;
QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
/* reply has finished, use it */
looks interesting, all i would need is a QObject deriving class similar to the QNetworkReply which would handle the request.
when i was playing with that code i had the problem that my implementation of QNetworkReply wouldn't wait for loop.exec() to be running and then the finished() SIGNAL wouldn't be received by the loop.
but isn't there something easier than to spawn a QEventLoop?
NOTE: the QNetworkReply and QNetworkAccessManager in the example from [1] is spawned inside the pthread, i however, need to be able to communicate with the QCoreApplication's even queue using SIGNALS and SLOTS since the object with the data in it comes from a different QThread (in this either the QCoreApplication or a special QThread).
using a Qt::QueuedConnection
i've also found [2] and maybe:
connect(src, SIGNAL(signal-signature), dest, SLOT(slot-signature), Qt::QueuedConnection);
is all i want but i doubt that.
links
[0] https://github.com/qknight/qt-fuse-example/blob/4d92a74fad22fd559588e58be67f766174c7efb8/qt-fuse/examplefs.cc#L74
[1] http://qt-project.org/wiki/ThreadsEventsQObjects#7494f2b4836907fc1c09311e3a0305e6
[2] emit Qt signal from non Qt Thread or ouside Qt main event loop with at 4.5
What you're likely facing is that QNetworkAccessManager internally uses threads to process http requests. That's why it "doesn't wait" for you. There's a rather simple modification needed to fix it:
QNetworkAccessManager qnam;
QEventLoop loop;
QNetworkReply *reply = qnam.get(QNetworkRequest(QUrl(...)));
QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
if (!reply->isFinished()) loop.exec();
Things to note when using QObjects in Multiple Threads
When the object that is the source of a signal lives (is instantiated in) a thread different than the thread of the object with slots, the connection will be of the QueuedConnection type automatically.
The real issue is: Each QObject has a thread affinity. The default affinity is the thread where the object was instantiated. You're not supposed to use such objects directly from other threads.
What you're likely doing is instantiating the sender and receiver objects in the same thread, but then emitting the signal from another thread. This is a source of potential errors error and leads to undefined behavior if the user of such an object is forcing a non-automatic direct connection.
Whenever you do emit object->signal(...), the following invariant should hold:
Q_ASSERT(QThread::currentThread() == object->thread());
Feel free to add those invariant checks in front of every emit() that you explicitly perform.
If the assertion fails, you need to use QObject::moveToThread to move the object to the thread where you want to fire its signals. You can get a QThread for a given pthread by calling QThread::currentThread() from the code that runs in the pthread. An instance of a QThread will be created automagically for you :)
Yes, you want the Qt::QueuedConnection method. But also ensure that you are using the multithreading Qt library. IIRC it is a build-time option.
See also: Qt documentation
I have some problems with Qt. I have a class with a signal who's parameters are strings, and a slot. I'm connecting the signal to the slot in the class constructor. Also, I'm creating a thread in the class constructor. The thread reads data from a server and updates the UI(emits the UpdateMe signal). This is how I connect the signal to the slot:
QObject::connect(this, SIGNAL(UpdateMe(string, string)), this, SLOT(ModifyUI(string, string)));
I have a QTreeWidget with some file names. When I rename a file I notify the server and the server notifies the other clients. When I connect a single client there is no problem, but when I connect more than one client a problem appears: when I notify the server from the second client(when I write into the socket) the following error appears:
QObject::connect: Cannot queue arguments of type 'QVector<int>'
I tried to register QVector with qRegisterMetaType but I also have a signal that is emited when I modify an QTreeWidgetItem(when I rename the item, for example) and I need to dissconnect this signal when I want to change the item's text. If I register QVector I can't dissconnect this signal and the signal is emited.
When you register the QVector, does your call look like this?
qRegisterMetaType<QVector<int> >("QVector<int>");
Once you make this call, you should be able to emit the QVector type over queued connections.
If I register QVector I can't dissconnect this signal and the signal is emited.
Registering a metatype shouldn't prevent you from disconnecting a signal. It just allows you to queue types that aren't already registered with the meta system.
Most of the time, errors which look like this seem to be a result of mixing up threads, and specifically with this one, in my (limited) experience, a result of attempting to manipulate GUI elements "held" in the GUI thread using commands run a worker QThread.
I say "held" because quite often you get a complaint/error/crash saying something like "QObject: Cannot create children for a parent that is in a different thread." (i.e. the GUI thread).
The solution: from a non-GUI QThread ALWAYS communicate with GUI elements using signals and slots.
I created a multithreaded application in Qt (4.7.2). Only the main thread has an event loop.
The issue is that sometimes I get the following warning in the console:
QObject::startTimer: timers cannot be started from another thread
After this happens, the app consumes 100% of CPU (I have a single core CPU). It seems, that the main thread consumes all of the CPU's resources. The program does not freeze, and everything still works.
When I stop the program in the debugger, I do not see my code in the call stack.
The problem is that I'm not using (explicitly, anyway) timers at all.
What could it be connected with? I know, that question is very common, but I can't even understand, what piece of code to show.
Thanks, to #vrince I've fixed the problem. I used signals/slots mechanism + Qt::QueuedConnection to communicate with GUI
For example, if I need to set text of QLabel from worker thread, I can make in my worker thread signal
void textChanged(QString);
then I connect this signal to the slot of QLabel using Qt::QueuedConnection
connect(worker, SIGNAL(textChanged(QString)), label, SLOT(setText(QString), Qt::QueuedConnection);
If I want to execute setText synchronously, I can use Qt::BlockingQueuedConnection
now in my worker thread I just emit signal:
emit textChanged(newText);
Also, it is possible to use QMetaObject functions to avoid signals and slots:
metaObject->invokeMethod(label, "setText", Qt::QueuedConnection, Q_ARG(QString, text));
One of several initially baffling PyQt "warnings" (with consequences) symptomatic of a single, classic cause: trying to manipulate GUI elements using a non-"application thread", without using signals and slots as you should.
See my answer here.