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
