g_thread_new y G_LOCK no funcionan [Solucionado]

Hola!!

El caso es que intento hacer un programita con hilos y no hay manera:

#include <gtk/gtk.h>

G_LOCK_DEFINE(lock_thread);

typedef struct DATA {

GtkWidget *window,*grid,*progress,*label;
GThread *thread_1,*thread_2,*thread_3;

} Data;

static void *thread_1_func (Data *app)
{
  int i;

  for (i = 0; i < 100; i++)
    {
      g_usleep (100000); /* 0.1 s */
      G_LOCK(lock_thread);
      gtk_progress_bar_pulse(GTK_PROGRESS_BAR(app->progress));
      gtk_label_set_text(GTK_LABEL(app->label),"11111111111111111111111111111111"); 
      printf("thread 1\n");
      G_UNLOCK(lock_thread);
    }

  return NULL;
}

static void *thread_2_func (Data *app)
{
  int i;

  for (i = 0; i < 100; i++)
    {
   
      g_usleep (200000);
      G_LOCK(lock_thread);
      gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(app->progress),0);
      gtk_label_set_text(GTK_LABEL(app->label),"      222222222222222222    "); 
      printf("         thread 2\n");
      G_UNLOCK(lock_thread);
    }

  return NULL;
}

static void *thread_3_func (Data *app)
{
  int i;

  for (i = 0; i < 100; i++)
    {
      g_usleep (300000);
      G_LOCK(lock_thread);
      gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(app->progress),1);
      gtk_label_set_text(GTK_LABEL(app->label),"33333333333333333333333333333333"); 
      printf("                 thread 3\n");
      G_UNLOCK(lock_thread);
    }

  return NULL;
}

int
main (int    argc,
      char **argv)
{
 

  Data *app = g_slice_new(Data);

  gtk_init (&argc, &argv);

  app->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_window_set_default_size (GTK_WINDOW (app->window), 200, -1);
  g_signal_connect(app->window, "destroy", gtk_main_quit, NULL);

  app->grid = gtk_grid_new();
  gtk_container_add (GTK_CONTAINER (app->window), app->grid);
 
  app->progress = gtk_progress_bar_new();
  gtk_grid_attach(GTK_GRID(app->grid),app->progress,0,0,1,1);

  app->label = gtk_label_new("label");
  gtk_grid_attach(GTK_GRID(app->grid),app->label,1,0,1,1);
 
  gtk_widget_show_all (app->window);

  app->thread_1 = g_thread_new ("one", (GThreadFunc)thread_1_func, app);
  g_thread_unref(app->thread_1);
 
  app->thread_2 = g_thread_new ("two", (GThreadFunc)thread_2_func, app);
  g_thread_unref(app->thread_2);
 
  app->thread_3 = g_thread_new ("tres", (GThreadFunc)thread_3_func, app);
  g_thread_unref(app->thread_3);

  gtk_main ();

  g_slice_free(Data,app);

  return 0;
}

Cuando lo ejecuto (unas veces sí otras no) obtengo estos errores o parecidos:

thread 1
         thread 2
thread 1
                 thread 3
thread 1
         thread 2
thread 1
thread 1
                 thread 3
         thread 2
thread 1

(vdlerp:6837): Pango-CRITICAL **: pango_cairo_show_layout: assertion `PANGO_IS_LAYOUT (layout)' failed
thread 1
         thread 2
thread 1
                 thread 3

(vdlerp:6837): Gtk-CRITICAL **: _gtk_css_computed_values_get_value: assertion `GTK_IS_CSS_COMPUTED_VALUES (values)' failed

(vdlerp:6837): Gtk-CRITICAL **: _gtk_css_computed_values_get_value: assertion `GTK_IS_CSS_COMPUTED_VALUES (values)' failed

(vdlerp:6837): Gtk-CRITICAL **: _gtk_css_computed_values_get_value: assertion `GTK_IS_CSS_COMPUTED_VALUES (values)' failed

(vdlerp:6837): Gtk-CRITICAL **: _gtk_css_computed_values_get_value: assertion `GTK_IS_CSS_COMPUTED_VALUES (values)' failed
Violación de segmento

Se supone que el G_LOCK es un mutex que impediría errore y no veo donde falla. ¿Que puede estar mal?.
Gracias.

Pues con esto parece que lo he resuelto. Pero ¿Alguien sabe por qué?. No veo la razón.

#include <gtk/gtk.h>
#include <string.h>

G_LOCK_DEFINE(lock_thread);

typedef struct DATA {

GtkWidget *window,*grid,*progress,*label;
gchar lit[128];
GThread *thread_1,*thread_2,*thread_3;

} Data;

static gboolean update(Data *app)
{
 
//G_LOCK(lock_thread);
gtk_progress_bar_pulse(GTK_PROGRESS_BAR(app->progress));
gtk_label_set_text(GTK_LABEL(app->label),app->lit); 
printf("%s\n",app->lit);
//G_UNLOCK(lock_thread);
 
return FALSE;
}

static void *thread_1_func (Data *app)
{
  int i;

  for (i = 0; i < 100; i++)
    {
      g_usleep (100000); /* 0.1 s */
      strcpy(app->lit,"hilo1");
      gdk_threads_add_idle ((GSourceFunc)update,app);
     
    }

  return NULL;
}

static void *thread_2_func (Data *app)
{
  int i;

  for (i = 0; i < 100; i++)
    {
   
      g_usleep (200000);
      strcpy(app->lit,"     hilo2");
      gdk_threads_add_idle ((GSourceFunc)update,app);
    }

  return NULL;
}

static void *thread_3_func (Data *app)
{
  int i;

  for (i = 0; i < 100; i++)
    {
      g_usleep (300000);
      strcpy(app->lit,"          hilo3");
      gdk_threads_add_idle ((GSourceFunc)update,app);
    }

  return NULL;
}

int
main (int    argc,
      char **argv)
{
 

  Data *app = g_slice_new(Data);

  gtk_init (&argc, &argv);

  app->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_window_set_default_size (GTK_WINDOW (app->window), 200, -1);
  g_signal_connect(app->window, "destroy", gtk_main_quit, NULL);

  app->grid = gtk_grid_new();
  gtk_container_add (GTK_CONTAINER (app->window), app->grid);
 
  app->progress = gtk_progress_bar_new();
  gtk_grid_attach(GTK_GRID(app->grid),app->progress,0,0,1,1);

  app->label = gtk_label_new("label");
  gtk_grid_attach(GTK_GRID(app->grid),app->label,1,0,1,1);
 
  gtk_widget_show_all (app->window);

  app->thread_1 = g_thread_new ("one", (GThreadFunc)thread_1_func, app);
  g_thread_unref(app->thread_1);
 
  app->thread_2 = g_thread_new ("two", (GThreadFunc)thread_2_func, app);
  g_thread_unref(app->thread_2);
 
  app->thread_3 = g_thread_new ("tres", (GThreadFunc)thread_3_func, app);
  g_thread_unref(app->thread_3);

  gtk_main ();

  g_slice_free(Data,app);

  return 0;
}

¿Que tiene de especial gdk_threads_add_idle ((GSourceFunc)update,app);?. ¿Por que funciona sin el G_LOCK?.
Gracias. !!!!

Las funciones de GTK no pueden llamarse desde otra tarea ajena a la propia librería, no son "thread safe".

Las funciones gdk_threads_add_idle, añaden a la cola de GTK la llamada a una función callback, que se ejecutará cuando no existan eventos pendientes de procesar, así mismo se adueña del lock global de GTK, de forma que ninguna otra tarea puede interrumpir la ejecución del código callback.

Otras funciones GTK de interés,

gdk_threads_enter/gdk_threads_leave, adquirir/liberar el lock global de GTK.
gdk_threads_init, inicializa el soporte de tareas en GTK.

Las funciones de GTK no pueden llamarse desde otra tarea ajena a la propia librería, no son "thread safe".

Las funciones gdk_threads_add_idle, añaden a la cola de GTK la llamada a una función callback, que se ejecutará cuando no existan eventos pendientes de procesar, así mismo se adueña del lock global de GTK, de forma que ninguna otra tarea puede interrumpir la ejecución del código callback.

Otras funciones GTK de interés,

gdk_threads_enter/gdk_threads_leave, adquirir/liberar el lock global de GTK.
gdk_threads_init, inicializa el soporte de tareas en GTK.

xae escribió:

Las funciones de GTK no pueden llamarse desde otra tarea ajena a la propia librería, no son "thread safe".

Las funciones gdk_threads_add_idle, añaden a la cola de GTK la llamada a una función callback, que se ejecutará cuando no existan eventos pendientes de procesar, así mismo se adueña del lock global de GTK, de forma que ninguna otra tarea puede interrumpir la ejecución del código callback.

Otras funciones GTK de interés,

gdk_threads_enter/gdk_threads_leave, adquirir/liberar el lock global de GTK.
gdk_threads_init, inicializa el soporte de tareas en GTK.

Gracias Xae por las respuestas (las dos wink ). Esto aclara mi duda en parte. Ya lo había leído. La cosa que no entiendo (no me expliqué bien) es por qué no funciona G_LOCK. En mi código (el primero) no hago una llamada "ajena a la propia librería", hago lo mismo que luego se hace en el segundo código en una subrutina que meto dentro de una función llamada con "add_idle", sólo que poniendo un G_LOCK.
Pero se supone que G_LOCK hace lo mismo ¿o no?. En la explicación pone que se "adueña del lock global de GTK". Vale, entonces ¿Para que sirven y como se usan los G_LOCK?.
Supongo que el asunto será precisamente ese adueñarse del lock global de GTK y de ahí viene mi comentario de que G_LOCK no funciona (o yo no sé como usarlo, que es más probable).

Vale. Pues me acabm de responder en un foro gringo. Ya sé lo que pasa.

El primer ejemplo coordina el lock entre los tres hilos, pero no entre ellos y el gtk_main... Ahí está el asunto de por que hace falta el add_idle, por que G_LOCK efectivamente no funciona como pensaba.
Y además está defenestrado. Como las mitades de la API de g_thread...

Pues hala, solucionado.

Un último apunte: gdk_threads_enter(); y leave están también defenestradas.