iwarv iwarv - 3 months ago 36
C++ Question

Qt: Signal main thread

Lots of similar questions exists, but no suitable answer found.

I use a 3rd party library.

When some of the virtual methods on the lib's classes are called, these are called from a worker thread that has not been started by my application. This thread is not a QThread, nor could it ever be.

I can emit from this thread, but only if I connect the slot using Qt::DirectConnection.
The upshot is that QObject::sender() in the SLOT will always return NULL.
I wish to call deleteLater() for instance, but that can only be scheduled in a QThread.

I think I need to get back to the main thread, but how can I signal the object on the main thread?

Example: when the below method is called, it is done so on a thread created by 3rd party library.

/*virtual*/ bool MediaPlayer::onEof()
{
stopTransmit();
emit sigFinished(); // slots only called if bound using Qt::DirectConnection
deleteLater(); // dtor is never called

return false;
}


The connection is made from within a non-QThread context also, as follows:

/*virtual*/ void
SipCall::state_answer_call::onEntering(SipCall& ref)
{
...
MediaPlayer* player = new MediaPlayer;
ref.connect(player, SIGNAL(sigFinished()), SLOT(slotMediaFinished()), Qt::DirectConnection);
...
}


Without the explicit
Qt::DirectConnection
,
SipCall::slotMediaFinished()
is never invoked.

Answer

When some of the virtual methods on the lib's classes are called, these are called from a worker thread that has not been started by my application. This thread is not a QThread, nor could it ever be.

You're somehow under a mistaken belief that it's a problem. It not. The thread where you emit signals is immaterial. It doesn't have to be started using QThread.

In fact, emitting a signal from a C callback is an idiomatic way of interfacing multithreaded C callback APIs to Qt. It is meant to work without any effort.

I can emit from this thread, but only if I connect the slot using Qt::DirectConnection.

That's not true. When the signals and slots live in different threads, you can only use direct connections if the slots/functors you connect to are thread safe. I doubt yours are, so you should not use direct connection. The automatic connection will do exactly what you need.

It doesn't work because the receiving SipCall instance doesn't live in a thread with a running event loop. You'll have to either move it to such a thread, or use a thunk functor living in the main thread as suggested in the G.M.'s answer to this question.

The problem with thunk functors is that they obfuscate thread ownership of the object you're invoking the methods on. Most likely the SipCall methods aren't thread-safe either, so by calling them from the main thread you're bound to break things. It's safest to move the player to the application thread, and ensure it's only used from that thread. You won't need thunk functors then.

If you want to see what ways there are of running some code (e.g. a functor) in a given thread, see this question.

Comments