Re: callback and thread



"DINH V. Hoà" <dinh enserb fr> writes:

I would like to know why I can't call a thread that modify a gtkwidget
in an callback function.

[...]

It hangs up as gdk_threads_enter is used.
I think that the problem comes from the fact that 2 calls of
gdk_threads_enter
are likely to be nested ... but it is in a different thread. I would
like to
understand what is the exact problem and if a solution exists.

Your specific problem is indeed that you call gdk_threads_enter() too
many times.  To get rid of the deadlock, try removing the
gdk_threads_enter()/gdk_threads_leave() pair around gtk_main(). 

But very likely, your real problem is in the design of your
application.  There are several possible reasons you might have to use
threads:

 a) asyncronous I/O. Threads is a simple way to provide asyncronous I/O
    without messing with non-blocking sockets.

 b) to take advantage of more than one CPU. If your threads are all
    doing calculations (as opposed to e.g. waiting for I/O as most
    programs do most of the time), the operating system may be able to
    schedule the threads on their own CPU.

 c) to have two or more things 'happen at the same time'. Used this
    way, threads is a design tool, but not a very good one. You have
    absolutely no control over which thread will be running when, and
    the synchronization issuses will easily turn into an unmaintable
    mess.

If you are using threads because of c), then stop doing that. What you
really want is either gtk_idle_add() or gtk_timeout_add(). These are
much easier to deal with. Remember to call gtk_main_iteration() once
in a while.

If you are using threads for reason a), then consider if you can do
with GIOChannels instead. If you can't, or you need to use threads to
take advantage of more than one CPU, then do something like the
following:

Implement a reentrant queue, that is a queue which you can safely
access from more than one thread at once. With luck, this could be the
only synchronization you'll need. Break your calculations into as
small pieces as you can and add them to the queue when you know you
need to calculate them. Have a number of threads that do basically:

while (1)
{
  Calculation *c;
  gpointer r;

  c = queue_read (); /* blocks if queue is empty, but that is OK */

  r = c->do_calculation (c->data);

  gtk_idle_add (c->return_func, c);
}

where Calculation could look like

typedef struct {
  gpointer data;
  void (* return_func) (gpointer result);
  gpointer (* do_calculation) (gpointer data);
} Calculation;

The main thread may then safely add calculations the can be done in
parallel to the queue and just be called when they are done.




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