qt - QProcess dies for no obvious reason -
while coding seemingly simple part of qt application run subprocess , read data standard output, have stumbled upon problem has me puzzled. application should read blocks of data (raw video frames) subprocess , process them arrive:
- start qprocess
- gather data until there enough 1 frame
- process frame
- return step 2
the idea implement processing loop using signals , slots – might silly in simple, stripped-down example provide below, seemed entirely reasonable within framework of original application. here go:
app::app() { process.start("cat /dev/zero"); buffer = new char[framelength]; connect(this, signal(wantnewframe()), slot(readframe()), qt::queuedconnection); connect(this, signal(frameready()), slot(framehandler()), qt::queuedconnection); emit wantnewframe(); }
i start here trivial process (cat /dev/zero
) can confident not run out of data. make 2 connections: 1 starts reading when frame needed , other calls data handling function upon arrival of frame. note trivial example runs in single thread connections made of queued type avoid infinite recursion. wantnewframe()
signal initiates acquisition of first frame; gets handled when control returns event loop.
bool app::readframe() { qint64 bytesneeded = framelength; qint64 bytesread = 0; char* ptr = buffer; while (bytesneeded > 0) { process.waitforreadyread(); bytesread = process.read(ptr, bytesneeded); if (bytesread == -1) { qdebug() << "process state" << process.state(); qdebug() << "process error" << process.error(); qdebug() << "qiodevice error" << process.errorstring(); qcoreapplication::quit(); break; } ptr += bytesread; bytesneeded -= bytesread; } if (bytesneeded == 0) { emit frameready(); return true; } else return false; }
reading frame: basically, stuff data buffer arrives. frameready()
signal @ end announces frame ready , in turn causes data handling function run.
void app::framehandler() { static qint64 frameno = 0; qdebug() << "frame" << frameno++; emit wantnewframe(); }
a trivial data processor: counts frames. when done, emits wantnewframe()
start reading cycle anew.
this it. completeness, i'll post header file , main() here.
app.h:
#include <qdebug> #include <qcoreapplication> #include <qprocess> class app : public qobject { q_object public: app(); ~app() { delete[] buffer; } signals: void wantnewframe(); void frameready(); public slots: bool readframe(); void framehandler(); private: static const quint64 framelength = 614400; qprocess process; char* buffer; };
main.cpp:
#include "app.h" int main(int argc, char** argv) { qcoreapplication coreapp(argc, argv); app foo; return coreapp.exec(); }
and bizarre part. program processes random number of frames fine (i've seen fifteen more thousand) stops , complains qprocess had crashed:
$ ./app frame 1 ... frame 245 frame 246 frame 247 process state 0 process error 1 qiodevice error "process crashed"
process state 0 means "not running" , process error 1 means "crashed". investigated , found out child process receives sigpipe – i.e., parent had closed pipe on it. have absolutely no idea of , why happens. else?
the code bit weird looking (not using readyread
signal , instead relying on delayed signals/slots). pointed out in discussion, you've seen thread on qt-interest ml asked similar problem. i've realized i, too, used queuedconnection
@ time. cannot explain why wrong -- queued signals "should work", in opinion. blind shot invokemethod
used qt's implementation somehow races signal delivery empty read buffer before qt gets chance process data. mean qt read 0 bytes , (correctly) interpret eof
, closing pipe.
i cannot find referenced "qt task 217111" anymore, there couple of reports in jira waitforreadyread
not working users expect, see e.g. qtbug-9529.
i'd bring qt's "interest" mailing list anmd stay clear of waitfor...
family of methods. agree documentation deserves updating.
Comments
Post a Comment