Ice::Thread and GUI with Qt

in Help Center
Hi!
I have an Ice application, where the server makes callbacks to the client, by means of proxy pointers which the client passes to it.
The client is to update its GUI based on the response received from the server, so I figured out that the right place to initialize the GUI is in the constructor of the callback proxy, which does something like the following, where the code in blue constructs a new Ice::Thread:
What I am trying to do is not to block the thread which receives the callback, with the GUI event loop. As you can see from the implementation of the qApplicationThread class, its sole purpose is to call guiApp->exec(); which blocks the thread in which it is called:
The servant makes the callback by calling the following method on the proxy object it has received. When the call is made, I update the image in the GUI:
This application design seems to be somehow faulty, because the client often dies out at startup with a segmentation fault, caused by a call deep down in the Qt library. When it does not die at start up, it always receives a Xlib: unexpected async reply (sequence 0x180)! error, after running a while. Sometimes is receives 2300 images before it causes this error.
I think the issue is not related so much to Ice, but is a basic design issue of multithreaded GUI applications.
Any good advice?
Thanks,
Catalin
I have an Ice application, where the server makes callbacks to the client, by means of proxy pointers which the client passes to it.
The client is to update its GUI based on the response received from the server, so I figured out that the right place to initialize the GUI is in the constructor of the callback proxy, which does something like the following, where the code in blue constructs a new Ice::Thread:
// ----------------------------------------------------------------------------------- ImageViewerI::ImageViewerI(int argcc, char *argvv[]) { // first initialize the imageViewer to some defaults argc = argcc; *argv = argvv[0]; app = new QApplication(argc, argv); ... imageViewer = new ImageViewer(params.imageWidth, params.imageHeight, 32); app->setMainWidget(imageViewer); imageViewer->show(); // let another thread run the GUI loop guiThread = [COLOR=blue]new qApplicationThread(argc, argv, app)[/COLOR] ; threads.push_back(guiThread->start()); ... }
What I am trying to do is not to block the thread which receives the callback, with the GUI event loop. As you can see from the implementation of the qApplicationThread class, its sole purpose is to call guiApp->exec(); which blocks the thread in which it is called:
qApplicationThread::qApplicationThread(int argc, char *argv[], QApplication *qa) { guiApp = qa; } void qApplicationThread::run() { guiApp->exec(); }
The servant makes the callback by calling the following method on the proxy object it has received. When the call is made, I update the image in the GUI:
// ----------------------------------------------------------------------------------- void ImageViewerI::acceptPacket(const ::dacapoCB::DCPacket& dcp, const ::Ice::Current&) { ... char *image = (char *)(&dcp[0]); imageViewer->updateImage(image + _DACAPO_PAYLOAD_OFFSET_, imageSize); ... } }
This application design seems to be somehow faulty, because the client often dies out at startup with a segmentation fault, caused by a call deep down in the Qt library. When it does not die at start up, it always receives a Xlib: unexpected async reply (sequence 0x180)! error, after running a while. Sometimes is receives 2300 images before it causes this error.
I think the issue is not related so much to Ice, but is a basic design issue of multithreaded GUI applications.
Any good advice?
Thanks,
Catalin
0
Comments
Hi cataling
the problem of your code is that qt don't suport that you call gui operations from other thread that is not the qt main thread where Qt::eventLoop is runing,
the correct way to solve this proble is dispacth a custom event from the oder thread and intercept this even't in your widget class
to dispach a custom event yo main call static function QApplication::postEvent( QObject * receiver, QEvent * event ) Note: This function is thread-safe when Qt is built withthread support.
Example
FileLoader implementation A widget thas's install the customEventFilter
the event and event filter implementation
I hope this code help you
One thing which worries me a little is the fact that my images arrive in a thread in a memory location pointed to by a char *. But this data is to be painted on screen by another thread, which gets this char *. In a way the two threads share data (memory) across thread boundaries. There are no concurrent accesse issues here, but still it seems so artificial to share data (memory) in this way. Is this fundamentally wrong?
Thanks,
Catalin
xdm is exactly correct. You cannot call Qt UI methods from any thread other than main. There is a chapter in the Qt documentation on exactly this topic. I recommend that you read it.
With respect to your concern. You should not pass the raw bytes to your main thread, but rather pass dcp in the QCustomEvent that you implement. What I recommend is that you setup a servant that has a copy of the display widget implementation. Perhaps something like this:
Then in the servant implementation you create an instance of this event and post it to the widget.
And then the widget implements customEvent as follows:
Of course, if there are lots of events then you can do something more elegant in customEvent.
Regards, Matthew
I have read the Qt doc about the main thread and multithreading when I first encountered the Xlib problem, but I was not aware that custom events would be an alternative to what I was trying to do, until xdm mentioned it for me. I will try it out as soon as I finish programming some other modules.
I am operating at 30 images per sec, on the maximum, so I am very curios if postevent will be processed often enough by Qt's runtime. I would prefer to be able to use sendevent, which I understand is synchronous, and publishes the event when it is called instead of placing it in a queue, but I could not see any mention that it is threadsafe, as postevent is documented to be.
So I am living in excitement....
Looking aside from the Qt issue, I still wonder if it is fundamentally correct to share memory between threads by means of pointers.
Some other place I am doing the following:
Is this all done by the book?
Again, thank you!
Catalin
This will not work, you must use post event to transfer the image to the main thread to be processed by the UI. The event queue will be processed at whatever speed your computer is capable of. If the software cannot keep up, then you will have to throttle the processing of the images, by dropping some.
This is a more general programming question. It is possible to share memory however you want, as long as it is suitably protected.
It is pretty inefficient. I would look at using a condition variable, or an Ice monitor. You can look at any MT programming book, or the Ice manual (check, for example, ice/demo/IceUtil/workqueue) for lots of examples of how to efficiently write producer/consumer style applications.
Regards, Matthew