GTK+ Forums Forum Index GTK+ Forums
Discussion forum for GTK+ and Programming. Ask questions, troubleshoot problems, view and post example code, or express your opinions.
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Gdk_threads[enter/leave]

 
Post new topic   Reply to topic    GTK+ Forums Forum Index -> GTK+ Programming
Author Message
killocan
Familiar Face


Joined: 23 Jan 2008
Posts: 18
Location: Brasil

PostPosted: Fri Apr 04, 2008 3:57 pm    Post subject: Gdk_threads[enter/leave] Reply with quote

Hello! Why i have to surround gtk_main() with gdk_threads_enter/leave ?
If i do, doesn't internal gtk code lock forever because of that? It makes
calls to GDK_THREADS_ENTER/LEAVE, so... if i lock it gtk will deadlock? don't?

Documentations notes:

from g_mutex_lock doc:

* GMutex is neither guaranteed to be recursive nor to be non-recursive,
i.e. a thread could deadlock while calling g_mutex_lock(), if it already
has locked mutex. Use GStaticRecMutex, if you need recursive mutexes.

But the gtk_threads_enter/leave impl, use GMutex:

from gdk.h:

Code: (Plaintext)
1
2
3
4
5

#if !defined (GDK_DISABLE_DEPRECATED) || defined (GDK_COMPILATION)
GDKVAR GMutex *gdk_threads_mutex; /* private */
#endif


from gdk.c:

Code: (Plaintext)
1
2
3
4
5
6
7
8
9
10
11
12
13
14

void
gdk_threads_init (void)
{
  if (!g_thread_supported ())
    g_error ("g_thread_init() must be called before gdk_threads_init()");

  gdk_threads_mutex = g_mutex_new ();
  if (!gdk_threads_lock)
    gdk_threads_lock = gdk_threads_impl_lock;
  if (!gdk_threads_unlock)
    gdk_threads_unlock = gdk_threads_impl_unlock;
}


and

Code: (Plaintext)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

static void
gdk_threads_impl_lock (void)
{
  if (gdk_threads_mutex)
    g_mutex_lock (gdk_threads_mutex);
}

static void
gdk_threads_impl_unlock (void)
{
  if (gdk_threads_mutex)
    g_mutex_unlock (gdk_threads_mutex);
}


So why this following code works? :)


Code: (Plaintext)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141

/*-------------------------------------------------------------------------
 * Filename:      gtk-thread.c
 * Version:       0.99.1
 * Copyright:     Copyright (C) 1999, Erik Mouw
 * Author:        Erik Mouw <J.A.K.Mouw@its.tudelft.nl>
 * Description:   GTK threads example.
 * Created at:    Sun Oct 17 21:27:09 1999
 * Modified by:   Erik Mouw <J.A.K.Mouw@its.tudelft.nl>
 * Modified at:   Sun Oct 24 17:21:41 1999
 *-----------------------------------------------------------------------*/
/*
 * Compile with:
 *
 * cc -o gtk-thread gtk-thread.c `gtk-config --cflags --libs gthread`
 *
 * Thanks to Sebastian Wilhelmi and Owen Taylor for pointing out some
 * bugs.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <gtk/gtk.h>
#include <glib.h>
#include <pthread.h>

#define YES_IT_IS    (1)
#define NO_IT_IS_NOT (0)

typedef struct
{
  GtkWidget *label;
  int what;
} yes_or_no_args;

G_LOCK_DEFINE_STATIC (yes_or_no);
static volatile int yes_or_no = YES_IT_IS;

void destroy (GtkWidget *widget, gpointer data)
{
  gtk_main_quit ();
}

void *argument_thread (void *args)
{
  yes_or_no_args *data = (yes_or_no_args *)args;
  gboolean say_something;

  for (;;)
    {
      /* sleep a while */
      sleep(rand() / (RAND_MAX / 3) + 1);

      /* lock the yes_or_no_variable */
      G_LOCK(yes_or_no);

      /* do we have to say something? */
      say_something = (yes_or_no != data->what);

      if(say_something)
    {
      /* set the variable */
      yes_or_no = data->what;
    }

      /* Unlock the yes_or_no variable */
      G_UNLOCK (yes_or_no);

      if (say_something)
    {
      /* get GTK thread lock */ // Gdk mutex is locked by main() code!
      gdk_threads_enter ();

      /* set label text */
      if(data->what == YES_IT_IS)
        gtk_label_set_text (GTK_LABEL (data->label), "O yes, it is!");
      else
        gtk_label_set_text (GTK_LABEL (data->label), "O no, it isn't!");

      /* release GTK thread lock */
      gdk_threads_leave ();
    }
    }

  return NULL;
}

int main (int argc, char *argv[])
{
  GtkWidget *window;
  GtkWidget *label;
  yes_or_no_args yes_args, no_args;
  pthread_t no_tid, yes_tid;

  /* init threads */
  g_thread_init (NULL);
  gdk_threads_init ();
  gdk_threads_enter ();

  /* init gtk */
  gtk_init(&argc, &argv);

  /* init random number generator */
  srand ((unsigned int) time (NULL));

  /* create a window */
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);

  gtk_signal_connect (GTK_OBJECT (window), "destroy",
              GTK_SIGNAL_FUNC (destroy), NULL);

  gtk_container_set_border_width (GTK_CONTAINER (window), 10);

  /* create a label */
  label = gtk_label_new ("And now for something completely different ...");
  gtk_container_add (GTK_CONTAINER (window), label);
 
  /* show everything */
  gtk_widget_show (label);
  gtk_widget_show (window);

  /* create the threads */
  yes_args.label = label;
  yes_args.what = YES_IT_IS;
  pthread_create (&yes_tid, NULL, argument_thread, &yes_args);

  no_args.label = label;
  no_args.what = NO_IT_IS_NOT;
  pthread_create (&no_tid, NULL, argument_thread, &no_args);

  /* enter the GTK main loop */
  gtk_main (); //MYNOTE: it will block here until GTK main loop returns!
  gdk_threads_leave ();

  return 0;
}



Another weird point on gdk threads docs is:

* Idles, timeouts, and input functions from GLib, such as g_idle_add(), are executed
outside of the main GTK+ lock. So, if you need to call GTK+ inside of such a callback,
you must surround the callback with a gdk_threads_enter()/gdk_threads_leave() pair
or use gdk_threads_add_idle_full() which does this for you.

But, gtk says to do not use gtk_idle_add, and to use g_idle_add() instead. Ok, so it
leave me no options :) i have to call gdk_threads_enter, even if it lead-me to a deadlock ? :)

NOTE: I have an application running and it calls gtk functions from glib idle functions
without problem, is it just luck? It also calls gtk_threads_enter before gtk_main and, i call sections that use these locks without problem :)

Thanks!!!
Back to top
killocan
Familiar Face


Joined: 23 Jan 2008
Posts: 18
Location: Brasil

PostPosted: Mon Apr 14, 2008 3:54 pm    Post subject: Any detail ? Reply with quote

There is any detail that i'm forgetting? :)
Back to top
killocan
Familiar Face


Joined: 23 Jan 2008
Posts: 18
Location: Brasil

PostPosted: Fri Apr 18, 2008 4:45 pm    Post subject: I think i get it! Reply with quote

Hi! i made some changes in the code. Now it just lock and unlock the mutex, and make a
trace of it:

Code: (Plaintext)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

#include <stdio.h>
#include <stdlib.h>
#include <gtk/gtk.h>
#include <glib.h>
#include <pthread.h>

void destroy(GtkWidget *widget, gpointer data)
{
  gtk_main_quit();
}

void *argument_thread(void *args)
{
  for(;;)
    {
      fprintf(stderr,"* GDK_THREADS_ENTER!\n");
      gdk_threads_enter();
      fprintf(stderr,"---------------> IN GDK_THREADS_ENTER!\n");
      gdk_threads_leave();
      fprintf(stderr,"* LEAVING GDK_THREADS_ENTER -> GDK_THREADS_LEAVE!\n");
    }

  return NULL;
}

int main(int argc, char *argv[])
{
  GtkWidget *window;
  pthread_t no_tid, yes_tid;

  g_thread_init(NULL);
  gdk_threads_init();

  fprintf(stderr,"# GDK_THREADS ENTER! (MAIN)\n");
  gdk_threads_enter();

  gtk_init(&argc, &argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

  gtk_signal_connect(GTK_OBJECT(window), "destroy",
                     GTK_SIGNAL_FUNC(destroy), NULL);

  gtk_widget_show(window);

  pthread_create(&yes_tid, NULL, argument_thread, &a);
  pthread_create(&no_tid, NULL, argument_thread, &b);

  fprintf(stderr,"# GTK_MAIN!\n");
  gtk_main();
  fprintf(stderr,"# LEAVING GTK_MAIN!\n");
  gdk_threads_leave();
  fprintf(stderr,"# LEAVING GDK_THREADS_ENTER -> GDK_THREADS_LEAVE! (MAIN)\n");

  return 0;
}


The output is:

killocan@localhost-marcos:~> ./gtk-thread
# GDK_THREADS ENTER! (MAIN)
# GTK_MAIN!
* GDK_THREADS_ENTER!
---------------> IN GDK_THREADS_ENTER!
* LEAVING GDK_THREADS_ENTER -> GDK_THREADS_LEAVE!
* GDK_THREADS_ENTER!
---------------> IN GDK_THREADS_ENTER!
* LEAVING GDK_THREADS_ENTER -> GDK_THREADS_LEAVE!
* GDK_THREADS_ENTER!
---------------> IN GDK_THREADS_ENTER!
* LEAVING GDK_THREADS_ENTER -> GDK_THREADS_LEAVE!

... GOES ON!

* GDK_THREADS_ENTER!
# LEAVING GTK_MAIN!
# LEAVING GDK_THREADS_ENTER -> GDK_THREADS_LEAVE! (MAIN)

Then i think, did gtk_main() unlock the mutex if its is locked?

And the answer is YES. The code bellow is a piece of gtk_main code:

Code: (Plaintext)
1
2
3
4
5
6
7
8
9

  if (g_main_loop_is_running (main_loops->data))
    {
      GDK_THREADS_LEAVE();
      g_main_loop_run (loop);
      GDK_THREADS_ENTER();
      gdk_flush ();
    }


Note: before it call the main event loop it realeases the gdk mutex.

Documentation note:
Docs from g_main_loop_run:
void g_main_loop_run(GMainLoop *loop);

Runs a main loop until g_main_loop_quit() is called on the loop. If this is called for
the thread of the loop's GMainContext, it will process events from the loop, otherwise
it will simply wait.

It means (IMHO) as gtk_main create the loop with:

Code: (Plaintext)
1
2
3

loop = g_main_loop_new (NULL, TRUE);


The first parameter (NULL) indicates to use the default main context. So it will process
events in a loop until g_main_loop_quit is called, AND without the mutex lock.

I guess, that's the answer to my question. If i'm wrong, please let me know!

Bye!
Back to top
Display posts from previous:   
Post new topic   Reply to topic    GTK+ Forums Forum Index -> GTK+ Programming All times are GMT
Page 1 of 1

 


Powered by phpBB © 2001, 2005 phpBB Group
CodeBB 1.0 Beta 2
Protected by Anti-Spam ACP