Re: Thread programming



On Mon, 2003-06-16 at 13:06, Tristan Van Berkom wrote:
Justin Hopper wrote:

On Mon, 2003-06-16 at 09:51, Tristan Van Berkom wrote:
 

Tristan Van Berkom wrote:

   

Justin Hopper wrote:

     

On Mon, 2003-06-16 at 06:41, Tristan Van Berkom wrote:


       

Justin Hopper wrote:

 

         

On Sun, 2003-06-15 at 07:03, Havoc Pennington wrote:


   

           

On Sat, Jun 14, 2003 at 04:39:24PM -0700, Justin Hopper wrote:  
     

             

I've read the FAQ on thread programming, but I must be missing 
something
fundamental on how they work.

Any help is greatly appreciated.
  
       
               

Thread lockups are generally one thread stuck on a lock that's owned
either by another thread or that was locked earlier by the same
thread.

     
             

One thing I should mention is that I only have one thread running 
in the
background.  I assume the GUI runs in it's own thread, so that would
make a total of two threads.  I'm not doing anything in the GUI 
when it
locks up, but perhaps it is have trouble just reading the label 
that was
updated in the background thread.  I should also mention that the
background thread never locks up either, it keeps trucking along.

Can anyone confirm whether or not doing simple thread programming will
work while using libglade?



   
           

When Havoc said he didnt think libglade was "thread-safe"; I dont 
know if he
meant the run time utility or the code that it generates. It is 
probable that glade
doesn't generate code with mutex locks on object access et cetera et 
cetera
but other than that, If you use glade to generate/parse an XML 
widget layout;
the job is quite simple.

- Use the glade_xml_get_widget(xml, "name") API
- Make _SURE_ that this is done in the same thread that you will 
access the "created objects"
- Use threads to do lengthly background jobs and dont update any GUI 
memory space objects
from that thread. (i.e. if you do a db query that returns 10 
elements every `n' millies; pass those
to the gui thread to update your "listview" or whatnot; dont update 
directly).
- If you use "sources" in your thread (i.e. g_timeout_add), make 
sure that your thread has its own
GMainLoop running.

If you follow this strict practice, I garauntee it will work. (well, 
it works for me ;-) )
There have been a bunch of extra stuff added to make thread 
programming in gtk
more solid et cetera since "gtk+-2.x" (i.e. gdk_threads_enter/leave) 
which allow you
to do even cooler stuff.

Note. gdk_threads_enter/leave are by no means nescisary if you 
follow the above prectice.
(I'm guessing that this is just a wrapper for some global mutex for 
the "drawing kit").

Also ofcourse I have to agree with Havoc about the backtrace;
may I recommend Valgrind ? it will tell you where and when a posix 
mutex
gets locked _or_ unlocked twice by the same thread (I though that was
pretty neat).

Cheers,
                  -Tristan
 
         

Thanks, Tristan (et al.).  This seems like a very logical approach. 
Just as a side note, I tried debugging the application with gdb, but it
only showed:

[New Thread 1080082400 (LWP 28716)]
[New Thread 1090956592 (LWP 28717)]

So, I would probably have to use something like Valgrind to see where
the collision is occuring.

However, I'd rather pursue the idea of sending a message to the main
thread to update the GUI, and have all GUI updates done through that. 
Now my question is obvious: how do I notify the main loop?  I saw a few
examples of gtk_signal_emit_*, but where do I catch these signals in the
gtk_main loop and update certain things?  Just to make sure I've given
the right background information:

// main.c
...
pthread_create(&check_tid, NULL, check_queues, window1);
...
gdk_threads_enter();
gtk_main ();
gdk_threads_leave();

The thread that is spun off will have data that needs to be passed to
the main loop for the GUI.  Using this method, do I need to enter and
leave threads in main.c or in the check_queues function?

Thanks again for all the help.


       

=== <snip from gdk_threads_enter doc> ==========
This macro marks the beginning of a critical section in which GDK and 
GTK+ functions can be called. Only one thread at a time can be in such 
a critial section.
==========< end snip >====================

I dont know if putting your gtk_main() inside a locked 
`gdk_threads_mutex' is common
practice or something like that but AFAIK, its useless if you dont 
plan on updating the
gui from more than one thread; and even then, you wouldnt put your 
entire gtk_main
between.

As for communication; you could do that a number of ways :-)

This could work,

 - Create a GQueue and a GMutex to handle the queue.
 - in your main (GUI updating) thread, create a g_timeout_add
   function and every once and a while, come and check the queue like so
   ...
   g_mutex_lock(queue_mutex);
   /* process data in queue */
   g_mutex_unlock(queue_mutex);
   ....

   - in your child thread; when you have ready data; lock your mutex,
   add data to the queue and unlock mutex.

It would usualy be nicer to be "event based" and use the GCond API but
that would defeat the purpose (putting the GUI thread to sleep *doh*). 
This
polling method should keep the GUI responsive.

Cheers,
                              -Tristan
     

Actualy, (*doh*) you could make a socket or a named pipe and write from the
child and read in the parent. This way you avoid dumb polling.
(why did I sugest that ?)

Cheers,
                   -Tristan
   


One thing I still don't understand: I only have one thread created, and
it just updates the text of some labels.  So, this thread is not
colliding with any other threads I've created, but perhaps is colliding
with the gtk_main() thread.  So basically, my check_queues thread is the
only thread that is making updates to the GUI, unless the gtk_main()
thread is trying to make updates to the widgets as well.

So creating a socket or named pipe would not seem to help me currently,
or creating another thread that just does GUI updates, as that is
basically all my current thread does.

I'm starting to think that I the gtk_main() thread is getting locked out
of reading/updating the widgets and that I just need to somehow get a
lock on these labels before I update them in the check_queues thread.  A
mutex would work great, except how would I get the gtk_main() thread to
even be aware of the mutex and use it.

Perhaps I'm going about this all wrong?
 

Ok, where did we start out.

==============<snip>==============
...

g_thread_init(NULL);
...
pthread_create(&check_tid, NULL, check_queues, window1);
... 
gdk_threads_enter();
gtk_main ();
gdk_threads_leave();


// check_queues.c
    while (1) {
      ...(check some mysql database for data)...
        gdk_threads_enter();
      label = lookup_widget(GTK_WIDGET(toplevel),"label_name");
      gtk_label_set_text(GTK_LABEL(label), "whatever");
      gdk_threads_leave();
    }

==============<snip>==============
I'm afraid this code _obviously_ locks up before you call gtk_main()
unless the freak occurence that your testing (1) in your while statement
at the same time.

gdk_threads_enter/leave are a mutex lock around a critical section. (can I be
more clear ?)

FORGET gdk_threads_enter/leave!

void main() {
...
g_thread_init(NULL);

g_io_channel_unix_somethingorother_new(hook to a pipe or socket or something
                                      to call, label_update_function);
...
pthread_create(&check_tid, NULL, check_queues, window1);
... 
gtk_main ();

}

label_update_function() {
    read(socket_fd, updated stuff from database);
    label = lookup_widget(GTK_WIDGET(toplevel),"label_name");
    gtk_label_set_text(GTK_LABEL(label), "whatever");
}



// check_queues.c

    while (mysql condition maybe ?) {
      ...(check some mysql database for data)...
      write(socket_fd, the data that should go on the label);
    }


I think we're suffering from a lack of proper communication.

I very much hope that this is clear to you now :-)

Cheers all!,
                    -Tristan

I think the body of this thread might be getting out of control.  I'm
tempted to clear it, but the mailing list etiquette cops will hunt me
down and destroy me.....

OK, I now fully understand, and thank you for posting that bit from the
threads doc, that entering and leaving threads is not going to be needed
in my app.

What I still don't understand: where is the collision occurring?  If I
only have one thread, and only that thread is making updates to the GUI,
why does the GUI itself (and I assume the gtk_main() thread), lock up? 
I think until I have an answer to this, I won't understand how any code
rework will help, as they should all run into the same problem of making
updates to the GUI and then having the GUI lock up.

Thanks for everyone's patience.





_______________________________________________
gtk-app-devel-list mailing list
gtk-app-devel-list gnome org
http://mail.gnome.org/mailman/listinfo/gtk-app-devel-list
-- 
Justin Hopper <gus gusalmighty com>




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]