Enable QT multi threading in the qtgui template

Hi,

In my quest to implement some OOT GUI widgets, I was hit by a number
of crashes because I need to do rendering (which includes some X/xcb
calls) from another thread than the main GUI thread.

Now, under QT it’s documented how to do it and it’s fairly painless
except that if you’re under linux and using X11, you need to call
XInitThreads() before doing any GUI stuff (so before creating the
QApplication for instance).

My current solution is to add this before creating the QApplication :

if os.name == ‘posix’:
x11 = ctypes.cdll.LoadLibrary(‘libX11.so’)
if x11:
x11.XInitThreads()

Does anyone see a better solution ?

Does that stand any chance of getting merged ?

Cheers,

Sylvain

On Wed, Sep 25, 2013 at 11:39 AM, Sylvain M. [email protected]
wrote:

Cheers,

Sylvain

Sylvain,

Have you solved your problem from yesterday with the OOT project
inheriting from the QTGUI blocks? Basically, it should be possible (at
least, I want it to be possible), but it’s probably never been done
before. I have tried to make sure everything’s been exported from
libgnuradio-qtgui to enable this, but I’ve never actually tried it.

And obviously, any patches you needed to make to the qtgui library for
this should go back into the main code to help this work better in the
future.

As to the posix/X11 issue. We do some similar stuff elsewhere for
different platform support, though mostly this is in the Cmake files.
It’s not out of the question what you’ve done. We’d have to look at it
in the bigger picture. Your checks around it look good, though, so it
seems harmless enough. I’m guessing that ctypes.cdll.LoadLibrary
returns None if libX11.so isn’t found?


Tom
GRCon13 Oct. 1 - 4
http://www.trondeau.com/grcon13

Hi,

Have you solved your problem from yesterday with the OOT project
inheriting from the QTGUI blocks?

No unfortunately. I made some progress though :

  • The QObject parent must be first in the inheritance.
  • Needed to include the Q_OBJECT macro in the class definition and
    also enable the “AutoMOC” in the CMakeFile.txt
  • Return a dynamic_casted pointer to QWidget* in pyqwidget() method
    rather than just “this”.

Now it runs fine and just crashes on cleanup/shutdown.

Whenever a QWidget is added to a parent, the parent takes ownership of
the pointer and so it will be deleted when deleting the parent. Then
it will be deleted as part of GR, so that’s the first issue.

But here I don’t even seem to get to that point because the destructor
is called only once (I have a printf in it) and it still crashes …
The Qt magic might be interfering with the SWIG magic …

I also tried creating the QWidget subclass separately, like it’s done
in the qtgui elements but I also have a problem on destruction because
there is a tight link between the two (exchanging a lot of data …)
and they’re destroyed independently by two completely different path

And it’s also not such a nice solution because of the many
interactions needed between the two classes it’d be much better to
have one single object be a descendant of both QGLWidget and
gr_sync_block

Basically, it should be possible (at
least, I want it to be possible), but it’s probably never been done
before. I have tried to make sure everything’s been exported from
libgnuradio-qtgui to enable this, but I’ve never actually tried it.

Well in this case I’m not really extending a qtgui block, just adding
a new one that has to integrate with the ‘top level’ of the existing
ones.

And obviously, any patches you needed to make to the qtgui library for
this should go back into the main code to help this work better in the
future.

For QT the only mod will probably be the multithread thing.
For WX on the other hand I’m still not sure how to make it work at all
and what kind of changes this would require.

But yeah, I definitely want this to work with an “out of the box” GR
and to get any required changes merged.

As to the posix/X11 issue. We do some similar stuff elsewhere for
different platform support, though mostly this is in the Cmake files.
It’s not out of the question what you’ve done. We’d have to look at it
in the bigger picture. Your checks around it look good, though, so it
seems harmless enough. I’m guessing that ctypes.cdll.LoadLibrary
returns None if libX11.so isn’t found?

Actually I though so, but under further checks it throws an OSError
exception so it would probably need to be wrapped in try catch.

Cheers,

Sylvain

I also tried creating the QWidget subclass separately, like it’s done
in the qtgui elements but I also have a problem on destruction because
there is a tight link between the two (exchanging a lot of data …)
and they’re destroyed independently by two completely different path

Ah, at least I found how to deal with that.

The default top level generated by GRC does something like this :

qapp = Qt.QApplication(sys.argv)
tb = top_block()
tb.start()
tb.show()
qapp.exec_()
tb.stop()
tb = None

Now the problem is that the Qt stuff will start to get cleaned up
before all the block stop() methods have run and so some processing
might still be going on while some Qt element get destroyed and then
all hell breaks loose ( abort / segfaults / exceptions / … )

Adding a tb.wait() right after the tb.stop() seems to fix the problem.
But it might even be better to register an “aboutToQuit()” signal
handler and issue the stop() & wait() to the flowgraph before any of
the Qt app cleanup even begins.
And this seems to fit the recommended usage
http://doc.qt.digia.com/4.7/qcoreapplication.html#aboutToQuit

And you get something like this :

qapp = Qt.QApplication(sys.argv)
tb = top_block()
tb.start()
tb.show()
def quitting():
    tb.stop()
    tb.wait()
qapp.connect(qapp, SIGNAL("aboutToQuit()"), quitting)
qapp.exec_()

Where the order of destruction makes more sense. You end up having :

  • All stop() method called and wait for completion of all
  • Destruction of all QWidgets by Qt
  • Destruction of all blocks themselves

This at least gives the opportunity to blocks that create some Qt
widget to know that they should stop accessing them because they
might not be there anymore … (in my case I start/stop a worker
thread in the gr::sync_block start/stop methods and that thread
accesses the QWidget create by the block)

Cheers,

Sylvain

Hi Tom,

Yes, the destruction of objects with QT being “good” and doing its own
garbage collection was a hassle for me at the beginning, too. This
looks like a nice solution, especially if it solves your issues.

I was hoping to be able to have the same class deriving from both
gr_sync_block and QWidget, but unfortunately that doesn’t seem
possible, but at least with this I can have both independently.

The downside is that it’s harder to make the 3 versions of the block
share some of the code. I have a glfw version that’s standalone and
doesn’t depend on any GR gui toolkit support and I wanted to make a Qt
and WX version that integrated nicely and share as much as possible of
the GR integration code, but you need to do stuff so differently for
the 3 toolkits that’s it’s pretty hard to come up with a good
solution.

Once you’ve settled everything and have your OOT module working and
tested, can you send us a couple of patches for these things? Or you
and I can work offline to make sure things are fixed correctly.

Yup of course.

I’d like to get WX to work as well so I know exactly all that needs to
be updated for it to all work together.

Cheers,

Sylvain

On Wed, Sep 25, 2013 at 6:10 PM, Sylvain M. [email protected]
wrote:

qapp = Qt.QApplication(sys.argv)

all hell breaks loose ( abort / segfaults / exceptions / … )
qapp = Qt.QApplication(sys.argv)

Cheers,

Sylvain

Excellent, Sylvain!

Yes, the destruction of objects with QT being “good” and doing its own
garbage collection was a hassle for me at the beginning, too. This
looks like a nice solution, especially if it solves your issues.

Once you’ve settled everything and have your OOT module working and
tested, can you send us a couple of patches for these things? Or you
and I can work offline to make sure things are fixed correctly.

Thanks!


Tom
GRCon13 Oct. 1 - 4
http://www.trondeau.com/grcon13