Hi John, Thanks for taking the time to provide such a great answer. I REALLY appreciate it.
I need to investigate semaphores more, but in the mean time, I'd like to try the first solution you gave (hopefully tonight or tomorrow). I have a question though. If I understand the first solution correctly, we're creating a separate idle function for each message. If the worker thread gets a bit ahead of the GUI updates, then a few idle functions might pile up. ok. But one thing I don't understand is that these idle functions will be spawned by the worker thread (not from the main gtk context), and I thought only the main gtk iteration was allowed to muck around with the textview (or any other part of the GUI). Originally I had the worker function attempting to update the textview, but it seg-faulted. Making an idle function spawned by the main gtk iteration do it solved the seg-faulting. Can I really have idle functions spawned from the worker thread update the textview? BTW, my program shouldn't fill memory because there's really only maybe a total of 40 to 50 lines of text - 1 line per message - to be put into the textview. Dave ________________________________ From: "jcup...@gmail.com" <jcup...@gmail.com> To: David Buchan <pdbuc...@yahoo.com> Cc: gtk-app-devel-list list <gtk-app-devel-list@gnome.org> Sent: Friday, July 6, 2012 3:56 AM Subject: Re: yet another thread question Hi again David, On Friday, 6 July 2012, David Buchan wrote: > > When the user presses a button, an idle function is begun to watch a flag > which will tell it a message has been left in a string for it by a worker > thread. The worker thread is then started. It will produce results to be > displayed in a textview by the idle function. When the worker thread has > results, it puts them into the string and sets the message_available_flag. > The idle function sees the flag set, prints the results to the textview, and > then clears the message_available_flag. There's a much simpler solution -- just malloc the string in the worker and pass it to the main thread as an idle argument. Something like: worker() { char *str; for(;;) { str = g_strdup("hello world!\n"); g_idle_add(from_worker_cb, str); sleep(1); } } gboolean from_worker(char *str) { update_textview(str); g_free(str); return FALSE; } Now there's effectively a flexible buffer between the worker and the main thread, so one can briefly run ahead of the other if it has to. As long as update_textview() typically takes less time than an iteration of your worker's loop, you'll be fine. If the worker is always very quick and textview is always very slow you could fill memory. But this is very unlikely: updating your program's model should be quick (or your program is badly designed) and an iteration of a worker should be slow (otherwise, why bother making a worker). You could make the buffer bounded with a semaphore. Something like: // start it at count 10 Semaphore *buffer_length = semaphore_new(10); worker() { char *str; for(;;) { // decrement the semaphore // if the semaphore is zero, block until it's >0 // then try again semaphore_down(buffer_length); str = g_strdup("hello world!\n"); g_idle_add(from_worker_cb, str); } } gboolean from_worker(char *str) { update_textview(str); g_free(str); // increment the semaphore // this will never block us, but can unblock anything // waiting on this semaphore semaphore_up(buffer_length); return FALSE; } Using locks and shared variables to synchronise threads can be very hard, as you found. Races and deadlocks will bite you badly, especially in more complicated situations. I find semaphores a nice abstraction: they encapsulate the slightly tricky process of read / lock / signal in a simple way. They are a bit old-fashioned now though, which is why I guess glib does not have a direct implementation. John _______________________________________________ gtk-app-devel-list mailing list gtk-app-devel-list@gnome.org https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list