PDA

View Full Version : Signal/Slot and other problem with producer/consumer thread(s)



donglebob
21st October 2008, 09:57
Hi,

I have a Producer-Thread which collects data all the time. This data is from low level, it cant understand the logic.

For this reason the producer thread sends the data to the correct Consumer-Thread.
(data-type0 to consumer0 etc...)

The consumer threads are created by the producer-thread dynamically.
I thought that sending the data from producer to consumer with signals/slots would be good for this situation. (so I need dynamic signal connections???)
After sending data to consumerN is finished producer has to resume its work, collecting other data.

The consumerN, which received the data, recognizes that data has arrived.
(SLOT was called by the signal connection).
The consumerN should now start to work on the received data to understand the logic behind it.

While consumerN is working on that data, producer should be able to collect other data.
The new data could be send to another conumer or the same conumerN again.

Meanwhile the user can change something on the GUI.
These changes must be emitted to the consumers. Every consumer has an own Tab (tab widget) with other elements on it .

I know that the other way, changing something on the GUI from the consumer-thread (non-gui-thread) ,is not possible.
The data, which die consumer get and understands should be printed in the GUI.
It can be a kind of Plot or some other changes.
Any Idea how I can do that?


But my main problem is following:

I want that my consumer-threads live as long as I want.
They should not die after working on one piece of data.
They should work on it and when finished they should wait (for example a wait condition).
And they should be able to receive Signals.

That means I need the call to exec() in my run() and I need an own loop where I work on my received data and after working wait with a wait-condition.
I dont know how to realize that. Need some help!

Something like that:

consumer:


void run() {

while(some_flag){

if(data_has_arrived) // flag ist set by my SLOT (producer sent a signal)
do_sth_with_data(); //work on data

WAIT_CONDITION_GOES_HERE // i think I should use it....

}

exec() // i must call this to receive signals

}



Here I can loop in my while(some_flag) or I can go to exec()
When I reach exec() i cannot go back to work on data, which will come later.

- I dont' want that the consumer Thread dies.
- It must be able to wait for signals ( for example new work)
- it must work on new received data, after working it must wait for new work


How can I do that?

I think User hb had a similar problem here ?!??!?!

http://www.qtcentre.org/forum/f-qt-programming-2/t-processevents-for-a-qthread-9195.html

but I couldn't really understand the sollution.

donglebob
22nd October 2008, 22:04
and ideas?
I really need some hint. Maybe my explaination was not good enough ??

wysota
22nd October 2008, 22:31
Have you seen all the examples related to wait conditions and producer/consumer approach in the docs and in Qt Quarterly?

donglebob
23rd October 2008, 22:01
thx for ur answer,

i will check QQ, and the others (one more time).

Is it theorotically possible to do what I want?
The worst thing is that i am sitting here on that implementation and the damn deadline comes near,...getting frustrated

I will check now the above things....

thx again

EDIT: Is there a standalone producer/consumer example or do you mean that in the waitcondition example?

donglebob
24th October 2008, 10:20
Soo, I checked them again but these docs do not answer the question I have.

Is it possible to run a threads run() in a forever-loop (do some work) and let someone else from outside connect a slot in that thread.

Today I had the following idea:

My Thread would include in its run() an instance of an ObjectX and its exec().
The thread itself would have the ability to get signals from outside (exec()) and the work, which must be done in a forever-loop, could be done in the ObjectX instance?????
Is that a good way of doing this?

muellerp
24th October 2008, 12:16
In case you have an event loop in the working thread, you don't need any wait condition or loop or whatever, as this is what the event loop is already.
So:
Within run, call exec() to start the event loop. It won't return till it get's the exit() call.

The event loop in the worker thread then waits till any signal arrives.

Implement a slot to compute in worker thread.
When the computing is done, just return from the slot and/or emit a signal to your GUI thread with the computed results, which then the GUI thread can display.

donglebob
27th October 2008, 09:08
Hi,

thx for your idea but I think that will not work in my case.
If I understood it right, the producer-thread which emits the signal executes the slot of the consumer-thread in its own context not in the thread context of the consumer.

I have to emit a Signal, with that signal I could/should transfer the data to the consumer-thread. (data = QByteArray)
In that slot the data must be processed.

If I am not right with the thread-context, this would work in my case.

Am I right?

wysota
27th October 2008, 10:49
If I understood it right, the producer-thread which emits the signal executes the slot of the consumer-thread in its own context not in the thread context of the consumer.
No, this is not true. The slot is called in the context of the receiving thread. If you don't want signals and slots, you can use custom events instead.

donglebob
27th October 2008, 11:02
Ohhhh

but I always read the opposite in the forum . Maybe I understood sth wrong, thx!

I can send an emit from my producer-thread, which calls the slot of consumer0,which will be definetly not executed in the context of my producer thread. GREAT!


Will my producer-thread wait now until the slot of consumer0 is finished?
I really wanted to avoid that, so my producer could proceed, sending data to other consumers, while conumer0 is executing its SLOT.

donglebob
27th October 2008, 14:53
Why is it necessary to run an event loop within each thread to which you want to connect signals? The reason has to do with the inter-thread communication mechanism used by Qt when connecting signals from one thread to the slot of another thread. When such a connection is made, it is referred to as a queued connection. When signals are emitted through a queued connection, the slot is invoked the next time the destination object's event loop is executed. If the slot had instead been invoked directly by a signal from another thread, that slot would execute in the same context as the calling thread.

I think my question above is solved with that sentence.

But is my data, which will be sent via the "emit sendData(data)", secure?
Will it be stored somewhere temporary , so the producer cannot change it while the signal is still in the queue.

wysota
27th October 2008, 23:13
Often there is a misunderstanding that comes from the fact that the QThread object that controls the thread doesn't really live in "its" thread but in the thread that created this object. Thus if you call a slot from the QThread object, by default it will be executed in the context of the thread that created the QThread object and not in the thread started by the QThread object.

donglebob
28th October 2008, 08:29
Confused now a little bit.....??!?!?
That means my consumer-slots will be executed in my producer thread??
And that means that all of them will be executed in my main-program because the Qthread object of my producer lives in the main-program.

wysota
28th October 2008, 08:43
That means my consumer-slots will be executed in my producer thread??
Hard to say without knowing your code structure. It's best to simply check it out using QThread::currentThreadId().

donglebob
28th October 2008, 10:49
I checked it with currentThreadId()
First I printed with qDebug(...) in my producer, after that emitted a signal, so my consumer slot would be called and done the same there.

In both cases the returned integer number is identic, soo that means same context,..damn!

What I do:

My producer-thread gets a signal from a sibling object, after that I read in my producer the data I need and do some checking. If necessery I create in that slot of my producer new consumer-threads.
After creating them I send them a signal to exec their slots.

slot of my producer:


void producer::dataisInside()
{
//1- reading data from a global thread safe storage
//2- checking the inside of the data, if a new woker is requiered

if(newWorkerIsRequired){
worker = new Worker();
//push the new worker instance in a list/pool
worker->start();

}

Qt::HANDLE a = QThread::currentThreadId();
qDebug("I am producer and my handle is %d",a);

}

My worker is a simply derived from QThread and provides one slot to handle the signal which is sent by the producer.



class Worker:: public QThread
{
....
protected:
void run();
public slots:
void testslot();


}





void Worker::testslot()
{
Qt::HANDLE b = QThread::currentThreadId();
qDebug("I am consumer and my handle is %d",b);

}


Maybe I should create my Workers somewhere else?
Is that the problem?

donglebob
28th October 2008, 14:12
I think I solved it.

There, where I created the workers I added the "moveToThread" function.



worker = new Worker();
....
worker->start();
worker->moveToThread(worker);


Now I get different Id's of each worker.

1)
Is this a dirty sollution?
Are there any dangers by doing it with moveToThread?

2)
I am creating my workers dynamically and each worker provides a slot with it.
But my producer should emit a signal to one worker not to all. (not a one signal to many slot connection)

So I need to create for each worker one unique signal (runtime)
What would you prefer?
I read the article http://doc.trolltech.com/qq/qq16-dynamicqobject.html
it sounds good, but do I need this really?

This is how the whole progress should work:

- producer gets data
- producer analyzes data, determines destination (worker) thread
- if not available creates worker
- transmits data to worker (signal)

There must be sth like a multiplexer which connects the signal to the right worker in dependence of the received/analyzed data.

wysota
28th October 2008, 17:17
How about using a thread pool (QThreadPool) and runnables (QRunnable) instead of your current design?

donglebob
28th October 2008, 22:00
thanks I will study them.

Btw, Part 2) is solved.
I made a dynamic connect / disconnect in dependence of incoming data.
After a second thought I found that i do not need many signals, just one signal in my producer is enough.

The signal will be connected to the slot of my desired thread, signal will be emitted and disconnected again.
Seems to be working ....