That indeed is a more elegant solution! I really feel that I'm learning one
step at a time... Regarding the use of g_atomic_int_..., I'm curious how you
fit his into the flow? Obviously T and G must be initialized to share a
stopping variable s. Who should create this variable? I would be interested
to see how you would amend your 1-direction solution so that it also
supports stopping.

Thanks!
Dov

2009/7/8 Terrence Cole <[email protected]>

> On Tue, 2009-07-07 at 10:56 +0300, Dov Grobgeld wrote:
> > Thanks a lot for the help.! I have now solved the problem by
> > introducing a GCond,called C below, into the flow. For posterity, here
> > is the modified flow, which is actually a general model of a
> > client-server interaction between a worker thread and the gui thread.
> >
> >    * W locks j->M through g_mutex_lock(j->M) so that G will not send
> > the condition signal until we are ready for it.
> >    * W fills in j with various info to display.
> >    * W calls g_idle_add(GSourceFunc(cb_update_job), j) to indicate to
> > G that there is info to display.
> >    * W waits on C through g_cond_wait(j->C, j->M). This will unblock
> > j->M and allow G to continue.
> >    * G is called in cb_update_job().
> >    * G updates the gui, also possibly updates j based on GUI interaction.
> >    * G does g_mutex_lock(j->M) which causes it to wait until W has
> > reached g_cond_wait().
> >    * G sends a condition signal through g_cond_signal(j->C)
> >    * G does g_mutex_unlock(j->M). This will allow W to take the lock
> > in g_cond_wait().
> >    * W wakes up and does a g_mutex_unlock(j->M) as it no longer needs
> > the lock on the mutex.
> >    * W examines the return info that G filled in into j and contiues
> > or aborts its operation.
> >
> > Quite complex I have to admit. Is there a simpler way to solve the
> > same problem (query/response)?
>
> Check out GAsyncQueue.  For 1-way traffic on a GAsyncQueue Q:
>    * W fills in j
>    * W does g_async_queue_push( Q, j )
>    * W does g_idle_add(GSourceFunc(cb_update_job),Q)
>    * G in cb_update_job does: j = g_async_queue_pop(Q);
>
> Internally, the GAsyncQueue is basically doing the logic you have above,
> but it's much easier to use and probably has more bug testing and
> performance polishing.
>
> The 2-way case is basically the same thing twice.  For GAsyncQueues Q
> and Q':
>    * W fills in j
>    * W does g_async_queue_push(Q,j)
>    * W does g_idle_add(GSourceFunc(cb_update_job),Q)
>    * G in cb_update_job does: j = g_async_queue_pop(Q);
>    * G modifies j
>    * G does a g_async_queue_push(Q',j)
>    * W does a j = g_async_queue_pop(Q')
>
> Note that this relies on Q' blocking W while it waits for a response,
> which will limit your throughput.  You will get much better performance
> if you organize your program to take advantage of the pipelining nature
> of the queue. That said, the trivial 2-queue case will not be slower
> than what you have already since it's doing the same thing.
>
> I usually end up with something simpler than full 2-way communication
> (or I go all the way to threaded modules).  For instance, if the status
> G is sending back is something trivial like "you should stop now", then
> using a g_atomic_int_* will be much cheaper, and simpler.
>
> Good Luck,
> -Terrence
>
> > Regards,
> > Dov
> >
> > 2009/7/7 Chris Vine <[email protected]>
> > >
> > > On Mon, 6 Jul 2009 17:13:07 +0300
> > > Dov Grobgeld <[email protected]> wrote:
> > >
> > > > I'm having a problem with GMutex under Windows that don't lock. The
> > > > behaviour is definitely different from that under Linux.
> > > >
> > > > The system is composed of to threads. A gui thread G and a worker
> > > > thread W. The ping pong between the threads via a mutex j->M should
> > > > work as follows. j is a job data structure that carries info between
> > > > the worker thread and the gui thread.
> > > >
> > > >    1. W locks j->M through g_mutex_lock(j->M) so that a subsequent
> > > > lock will block.
> > > >    2. W fills in j with various info to display.
> > > >    3. W calls g_idle_add(GSourceFunc(cb_update_job), j) to indicate
> > > > to G that there is info to display.
> > > >    4. W blocks on M through a second call to g_mutex_lock(j->M)
> > > >    5. G is called in cb_update_job() and updates the gui, also
> > > > possibly updates j, and then does g_mutex_unlock(j->M)
> > > >    6. W wakes up and does a g_mutex_unlock(j->M) as it no longer
> > > > needs the lock on the mutex.
> > > >    7. W examines the return info that G filled in into j and contiues
> > > > or aborts its operation.
> > > >
> > > > The problem on Win32 is that g_mutex_lock in 4 doesn't block and the
> > > > thread continues, which eventually will cause the system to crash.
> > > >
> > > > Is something supposed to be different under Windows, or should I file
> > > > a bug?
> > >
> > > This won't work.  Mutexes have ownership once locked.  An unlock
> > > operation on a mutex must be carried out by the same thread that locked
> > > it.
> > >
> > > You could use condition variables to achieve what you want.  It would
> > > also be wise to read up a little more on threading, and in particular
> > > pthreads (which GThreads mimic).
> > >
> > > Chris
> > >
> > _______________________________________________
> > gtk-list mailing list
> > [email protected]
> > http://mail.gnome.org/mailman/listinfo/gtk-list
>
>
_______________________________________________
gtk-list mailing list
[email protected]
http://mail.gnome.org/mailman/listinfo/gtk-list

Reply via email to