Trolltech Home | Qt-interest Home | Recent Threads | All Threads | Author | Date
All threads index page 1

Qt-interest Archive, November 2007
Thread Synchronization Problem


Message 1 in thread

Hello,

I am using QThreads to have two processes running at the same time
which can send signals to each other. This works perfectly fine,
however, I have problems with the synchronization.

The first thread is supposed to send a pointer to data to the second
thread using SIGNAL/SLOT. The second thread uses this data and
afterwards the first thread deletes the data.

First, I tried sth like this:

//Thread1:
emit imageReady(image); //Thread2 displays the image
delete image;

The problem is now that if I use this like this, the image is deleted
before the emitted function in Thread2 can actually use it - I get a
segmentation fault. As a solution, I need a way to let the first
thread wait for the SLOT-function in the second thread end.

So I thought of using a mutex object to block the first thread while
the second performed. I ended up with sth like this:

//Thread1
QMutex mutex;

emit imageReady(image,&mutex);
mutex.lock();

//Thread2 in the SLOT function I then used
QMutexLocker(mutex);

Unfortunately, I still have the same problem as before: When the
emit-slot is not called before the mutex.lock() in Thread 1, it does
not get hold of the mutex and the program crashed once more.

Do you have any ideas how to let the first thread wait for the second
to end its called SLOT function?

Any help is highly appreciated, I have been trying for a while..

Thanks in advance and greetings,
Tim

--
 [ signature omitted ] 

Message 2 in thread

Tim Kietzmann wrote:
> Hello,
> 
> I am using QThreads to have two processes running at the same time
> which can send signals to each other. This works perfectly fine,
> however, I have problems with the synchronization.
> 
> The first thread is supposed to send a pointer to data to the second
> thread using SIGNAL/SLOT. The second thread uses this data and
> afterwards the first thread deletes the data.

Is there a reason you can't have the second thread delete the data when 
it's finished?  Or possibly use a wait condition to signal that a thread 
is done with the image.  Then have the first thread wait on that 
condition, and have the second call wakeAll when it's finished with the 
image.  The first thread can then wake up and delete it.

Darrik

--
 [ signature omitted ] 

Message 3 in thread

Em Thursday 01 November 2007 16:24:56 Tim Kietzmann escreveu:
> I am using QThreads to have two processes running at the same time
> which can send signals to each other. This works perfectly fine,
> however, I have problems with the synchronization.
>
> The first thread is supposed to send a pointer to data to the second
> thread using SIGNAL/SLOT. The second thread uses this data and
> afterwards the first thread deletes the data.
>
> First, I tried sth like this:
>
> //Thread1:
> emit imageReady(image); //Thread2 displays the image
> delete image;

If you upgrade to Qt 4.3, you can use the Qt::BlockingQueuedConnection 
signal-slot connection type.

That will make the Thread2's slot finish processing (i.e., return from the 
slot) before the emit line finishes.

-- 
 [ signature omitted ] 

Attachment: signature.asc
Description: This is a digitally signed message part.


Message 4 in thread

On 01.11.07 17:40:52, Thiago Macieira wrote:
> Em Thursday 01 November 2007 16:24:56 Tim Kietzmann escreveu:
> > I am using QThreads to have two processes running at the same time
> > which can send signals to each other. This works perfectly fine,
> > however, I have problems with the synchronization.
> >
> > The first thread is supposed to send a pointer to data to the second
> > thread using SIGNAL/SLOT. The second thread uses this data and
> > afterwards the first thread deletes the data.
> >
> > First, I tried sth like this:
> >
> > //Thread1:
> > emit imageReady(image); //Thread2 displays the image
> > delete image;
> 
> If you upgrade to Qt 4.3, you can use the Qt::BlockingQueuedConnection 
> signal-slot connection type.

Sorry for stealing the thread a bit, but I've got one question regarding
the blockingqueue connectiong:

Does it also work between gui and non-gui thread, if my non-gui-thread
doesn't run an even loop?

Andreas

-- 
 [ signature omitted ] 

Message 5 in thread

Em Thursday 01 November 2007 16:55:58 Andreas Pakulat escreveu:
> Does it also work between gui and non-gui thread, if my non-gui-thread
> doesn't run an even loop?

It works, but not how you're probably expecting.

Like the DirectConnection, BlockingQueuedConnection will only return once the 
target slot has returned. In the mean time, the thread emitting the signal is 
suspended and will not deliver even the next slot.

Now, it "works" if you don't have an event loop: it blocks until the slot 
returns. And here's the catch: if there's no event loop, the slot never 
called, therefore it never returns and, therefore, the calling thread blocks 
forever.

However, if the target thread creates an event loop and exec()s it, the signal 
is then delivered and the emitting thread will continue.

In other words: you can use BlockingQueuedConnection to send to a thread that 
hasn't created an event loop *yet*. That means you don't need to write 
synchronisation code to make sure the event loop has started.

-- 
 [ signature omitted ] 

Attachment: signature.asc
Description: This is a digitally signed message part.


Message 6 in thread

On Donnerstag, 1. November 2007, Thiago Macieira wrote:
> Em Thursday 01 November 2007 16:55:58 Andreas Pakulat escreveu:
> > Does it also work between gui and non-gui thread, if my
> > non-gui-thread doesn't run an even loop?
>
> It works, but not how you're probably expecting.
>
> Like the DirectConnection, BlockingQueuedConnection will only return
> once the target slot has returned. In the mean time, the thread
> emitting the signal is suspended and will not deliver even the next
> slot.

Thats exactly what I expected :)

> Now, it "works" if you don't have an event loop: it blocks until the
> slot returns. And here's the catch: if there's no event loop, the
> slot never called, therefore it never returns and, therefore, the
> calling thread blocks forever.

Well, I said between non-gui-thread and gui-thread and I meant sending a 
signal from the non-gui-thread, so the event loop will certainly run in 
my case - no matter what.

Wow, that makes my current code again a bit easier, thanks TT :)

Andreas

-- 
 [ signature omitted ] 

Message 7 in thread

Andreas Pakulat wrote:
>Wow, that makes my current code again a bit easier, thanks TT :)

I wanted to add a SynchronousConnection mode, which is DirectConnection 
for same-thread but BlockingQueuedConnection for cross-thread signal 
emission.

However, there's a problem if the object you're sending a message to is 
moving to your thread. It deadlocks as well, so there's no advantage to 
BlockingQueuedConnection.

-- 
 [ signature omitted ] 

Attachment: signature.asc
Description: This is a digitally signed message part.


Message 8 in thread

Hi Tim,

On Thursday 01 November 2007, Tim Kietzmann wrote:
> Hello,
>
> I am using QThreads to have two processes running at the same time
> which can send signals to each other. This works perfectly fine,
> however, I have problems with the synchronization.
>
> The first thread is supposed to send a pointer to data to the second
> thread using SIGNAL/SLOT. The second thread uses this data and
> afterwards the first thread deletes the data.
>
> First, I tried sth like this:
>
> //Thread1:
> emit imageReady(image); //Thread2 displays the image
> delete image;
The problem here is that signal/slots working across threads use queued 
connections. This means that first of all your receiver thread *must* have 
its event loop running (by calling exec()) and that you cannot predict 
exactly when the second thread will call the slot as it depend upon how many 
other events it is processing.

In the above code the emit call returns immediately as it just queues up an 
event in thread 2's event list.

Ways around this are to simply get thread 2 to delete the data when it is done 
with it, or to get thread 2 to emit another signal e.g. finishedWithData() 
which calls a slot on thread 1 which can then delete the data. Although this 
seems unnecessary.

Hope this helps,

Sean

--
 [ signature omitted ] 

Message 9 in thread

On 01.11.07 16:24:56, Tim Kietzmann wrote:
> I am using QThreads to have two processes running at the same time
> which can send signals to each other. This works perfectly fine,
> however, I have problems with the synchronization.
> 
> The first thread is supposed to send a pointer to data to the second
> thread using SIGNAL/SLOT. The second thread uses this data and
> afterwards the first thread deletes the data.
> 
> First, I tried sth like this:
> 
> //Thread1:
> emit imageReady(image); //Thread2 displays the image
> delete image;
> 
> The problem is now that if I use this like this, the image is deleted
> before the emitted function in Thread2 can actually use it - I get a
> segmentation fault. As a solution, I need a way to let the first
> thread wait for the SLOT-function in the second thread end.

That can only happen if you send around a pointer to the image instead
of a copy. So one possible fix is to let the signal take a copy of the
image and make sure its a deep copy.

> So I thought of using a mutex object to block the first thread while
> the second performed. I ended up with sth like this:

Mutex is the wrong thing for synchronization, either use a
QWaitCondition or a QSemaphore. A Mutex just makes sure that only 1
therad can access a certain routine at a time.

Another option to fix this is don't send the image at all. It seems your
two threads know about each other so its not a problem to store the
image as member variable of thread one, provide three accessor methods
(getImage,setImage and deleteImage) and protect each ones code with a
QMutexLocker. Then thread 1 sets the image before emitting the signal,
thread 2 gets the image and when its done processing it it deletes it.

If you don't want the two threads to know anything about each other you
need to emit a deep copy of the image.

Oh, and of course make sure you have QueuedConnections between the
threads and not direct connections.

Andreas

-- 
 [ signature omitted ] 

Message 10 in thread

Tim Kietzmann wrote:
> First, I tried sth like this:
> 
> //Thread1:
> emit imageReady(image); //Thread2 displays the image
> delete image;
> 
> The problem is now that if I use this like this, the image is deleted
> before the emitted function in Thread2 can actually use it - I get a
> segmentation fault. As a solution, I need a way to let the first
> thread wait for the SLOT-function in the second thread end.

Is there any particular reason why 'image' is a pointer? Or an even better 
question, why does the signal have to pass by pointer? If you are using QImage 
(which is implicitly shared and cheap to copy), you could make the signal emit 
by reference or value, e.g.:

     void imageReady(const QImage &image);

Your slot would also have to get the image by reference or value. Then when 
you emit:

     emit imageReady(*image);
     delete image;

For all the queued connections, Qt will automatically copy the image when 
posting the event to the receiver objects. The only thing you have to do is 
tell Qt how to make a copy of the image:

     qRegisterMetaType<QImage>("QImage");

(See also examples/thread/mandelbrot/..., which does exactly this.)

-- 
 [ signature omitted ]