 |
GTK+ Forums Discussion forum for GTK+ and Programming. Ask questions, troubleshoot problems, view and post example code, or express your opinions.
|
|
|
| Author |
Message |
|
|
killocan Familiar Face
Joined: 23 Jan 2008 Posts: 18 Location: Brasil
|
Posted: Fri Apr 04, 2008 3:57 pm Post subject: Gdk_threads[enter/leave] |
|
|
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
|
Posted: Mon Apr 14, 2008 3:54 pm Post subject: Any detail ? |
|
|
| There is any detail that i'm forgetting? :) |
|
| Back to top |
|
 |
killocan Familiar Face
Joined: 23 Jan 2008 Posts: 18 Location: Brasil
|
Posted: Fri Apr 18, 2008 4:45 pm Post subject: I think i get it! |
|
|
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 |
|
 |
|
Powered by phpBB © 2001, 2005 phpBB Group CodeBB 1.0 Beta 2
|