PDA

View Full Version : QThread and signals



bunjee
27th March 2008, 01:04
Hey there,

I'm using two threads : one for my GUI, one for my network library.
Here is my network library run function:


/* virtual */ void ZePurpleApi::run()
{
(...)

GMainLoop *loop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(loop);

// Qt never gets there

exec();
}

- The library I'm using requires : g_main_loop_run(loop);
- Between my two threads I'm communicating using signals.
- I need to call exec() to receive signal from my GUI main thread.

Is it possible to exec the thread and then start the g_main_loop_run(loop); ?

Thanks.

gabe
27th March 2008, 02:31
Could you time share the two event loops? Something like this:



bool run = true;
while(run)
{
QEventLoop eventLoop;
GMainLoop *loop = g_main_loop_new(NULL, FALSE);

eventLoop.processEvents(AllEvents, 100ms);

g_main_context_prepare();
g_main_context_query();
g_main_context_check();
g_main_context_dispatch();
}


Simulating running both the event loops in a single thread.

bunjee
27th March 2008, 10:13
Hmm,

This looks like a "hack" is there a more proper way to do it ?

bunjee
27th March 2008, 10:43
This is how I'm currently doing :

My Thread run function:



/* virtual */ void ZePurpleApi::run()
{
// Starting event loop
exec();
}

The slot I'm calling right after thread->start:


void ZePurpleApi::onThreadStart()
{
// We are in the good thread here
g_print("ZePurpleApi - onThreadStart %d\n", currentThreadId());

InitPurpleApi();

GMainLoop *loop = g_main_loop_new(NULL, FALSE);

// Unfortunately the g_main_loop appears to block the Qt event loop
g_main_loop_run(loop);
}

I think I cannot adopt your approach sincie I need my init Before the g_main_loop_run(loop); and after the exec(); otherwise my lib signals aren't propagated correctly in the proper thread.

Anybody has an idea?

bunjee
27th March 2008, 12:57
I think I figured out what's wrong, I'll keep you posted.

gabe
27th March 2008, 13:23
Yeah, I agree its a hack.

What I discovered, and what may be of help, is that the exec() call on QThread essentially creates a QEventLoop and calls exec() on it.

So, you can create the event loop yourself.

The interesting thing (at least for me) was that if I created the event loop myself it would 'catch' signals before disappearing into event(). Also, you can signal to another thread that this threads event loop is ready and will receive events.



run()
{
QEventLoop eventLoop;
emit eventLoopInited();
eventLoop.exec();
}

onThreadDoSomething()
{
// Do some work here...
}


In another thread:


onEventLoopInitied()
{
emit threadDoSomthing();
}


The event loop will receive and queue events it receives between its constructor and the call to exec(). Obviously, it doesn't process them untill exec(), but this solved my problem.

Anyway, best of luck. Please share your solution. I'd like to know how you manage to get to concurrent event loops playing nicely. :D

bunjee
27th March 2008, 14:41
Hey there,

I'm back after some refining of my thread.
here it is:


void ZePurpleThread::run()
{
g_print("PIKAAAAAABOOOOOOOOOOOOOO\n");
mPurpleApi = new ZePurpleApi();
mServiceApi = mPurpleApi;
mPurpleApi->Init();

GMainLoop *loop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(loop);
exec();
}

I just can't get working those two loops together.
I tried several solutions, here is what I did :


- Run the thread.
- Create my object.
- Start object loop.
- Run Exec.
=> Doesn't work


- Run the thread.
- Create my object.
- Run Exec.
- Start object loop.
=> Doesn't work



- Run the thread.
- Create my object.
- Run Exec.
- Catch the "started()" signal.
- Emit a signal to start the object loop in its own thread
=> Doesn't work

That's not possible to get g_main_loop_run() and exec() work altogether in a thread.
So we need to find a non blocking solution either for exec() or g_main_loop_run().

Has somebody ever coded this ?

bunjee
27th March 2008, 15:43
Got it:


void ZePurpleThread::run()
{
g_print("ZePurpleThread - run\n");

mPurpleApi = new ZePurpleApi();
mServiceApi = mPurpleApi;
mPurpleApi->Init();

g_timeout_add(100, ZePurpleThread::timerUpdate, NULL);

GMainLoop *loop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(loop);
}

gboolean ZePurpleThread::timerUpdate(gpointer data)
{
//g_print("ZePurpleThread - timerUpdate\n");
QEventLoop eventLoop;
eventLoop.processEvents();

return true;
}

rishid
28th March 2008, 02:44
Is this the cleanest way? I literally just came to the forum since I am doing the same thing as you and it was the first thread on the list.

I am currently doing this a really nasty hack and needed a new idea. In summary, it does the processing I need the thread to do (my network thread needs QTimer so events are needed), and then creates a timer that calls exit() 1 second later, and then runs exec(). I just hope exec() clears all the events in 1 second and then the exit() timer goes off and I am back. :crying:

Here is my code:



void NetThread::run()
{
NetMsg currentMsg;

while (1)
{
if (NetMsgQueue.isEmpty())
{
msleep(5);
}
else
{
/* Lock ? */
#warning ADD MUTEX HERE
currentMsg = NetMsgQueue.dequeue();

printf("Something in NetThread queue, processing it\n");

switch(currentMsg.type)
{
case NET_MSG_TYPE_SEND:
printf("Send message found, processing it\n");
writePkt(currentMsg.pPktDesc);
break;

case NET_MSG_TYPE_RECEIVE:
processPacket(currentMsg.pPktDesc);
break;
default:
/* Unknown Msg Type */
break;
}
}

QTimer *exitTimer = new QTimer();
connect(exitTimer, SIGNAL(timeout()), this, SLOT(killEventLoop()));
exitTimer->setSingleShot(true);
#warning find good time value
exitTimer->start(1000);
exec();
}
}

void killEventLoop() { exit(); }