GTK+ Forums

Discussion forum for GTK+ and Programming. Ask questions, troubleshoot problems, view and post example code, or express your opinions.
It is currently Fri Apr 18, 2014 3:48 pm

All times are UTC




Post new topic Reply to topic  [ 13 posts ] 
Author Message
 Post subject: gtk_dialog_run fails
PostPosted: Tue May 01, 2012 11:55 am 
Offline
Familiar Face

Joined: Thu Mar 29, 2012 9:40 am
Posts: 14
Hi all!!! The function gtk_dialog_run crashes when it is in another thread. This is my code

Code:
#include <gtk/gtk.h>
#include <stdlib.h>
#include <pthread.h>

GtkWidget *window;

gint delete_event( GtkWidget *widget, GdkEvent  *event, gpointer data )
{
    gtk_main_quit ();
    return FALSE;
}

void *thread_dialog()
{
   GtkWidget  *label;                               
   GtkWidget *dialog=gtk_dialog_new();
   label=gtk_label_new("just a label");
   
   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),label, TRUE, TRUE, 0);
   
   gtk_widget_show(label);
                                                 
   gtk_dialog_add_button(GTK_DIALOG(dialog),"Accept",GTK_RESPONSE_ACCEPT);
   gtk_dialog_add_button(GTK_DIALOG(dialog),"Reject",GTK_RESPONSE_REJECT);
   gint ret= gtk_dialog_run (GTK_DIALOG (dialog));                                               
   /* take action depending on ret */
   printf("value=%d\n",ret);
   gtk_widget_destroy(dialog);
   return NULL;
}

void init_dialog()
{
   pthread_t dialog_req;
   if(pthread_create(&dialog_req,NULL,thread_dialog,NULL)!=0)
      perror("error creating tread\n");   
}

int main(int argc, char *argv[])
{   
    GtkWidget *button;
    GtkWidget *box1;
    gtk_init (&argc, &argv);
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    g_signal_connect (G_OBJECT (window), "delete_event",G_CALLBACK (delete_event), NULL);
   
    box1 = gtk_hbox_new (FALSE, 0);
    gtk_container_add (GTK_CONTAINER (window), box1);
    button = gtk_button_new_with_label ("Button 1");
    g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (init_dialog), (gpointer) "button 1");
    gtk_box_pack_start (GTK_BOX(box1), button, TRUE, TRUE, 0);
    gtk_widget_show (button);
    gtk_widget_show (box1);
    gtk_widget_show (window);
   
    gtk_main ();
    return 0;
}


When I press "button", a new thread is executed, and dialog is created, but when it reaches gtk_dialog_run, the program quit.

why??
this is the output:
Code:
[xcb] Unknown sequence number while processing queue
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that.
test: ../../src/xcb_io.c:273: poll_for_event: Assertion `!xcb_xlib_threads_sequence_lost' failed.


I have tried to add "g_thread_init(NULL);" and " gdk_threads_init();" before gtk_init, but with the same result.


Thank you very much!!


Top
 Profile  
 
 Post subject: Re: gtk_dialog_run fails
PostPosted: Wed May 02, 2012 5:07 am 
Offline
Familiar Face

Joined: Tue Aug 18, 2009 5:02 pm
Posts: 23
Location: Vancouver, B.C.
From what I recall you're supposed to wrap all GTK calls in a thread with gdk_threads_enter and gdk_threads_leave.

However, my experience is that trying to do anything with GTK in a thread is a bit dodgy. I used to update widgets in a thread by setting the value of an adjustment that was attached to a spin control but ever since the upgrade to GTK3 it has caused segmentation faults.

By the looks of it your code isn't doing anything that requires a thread, any reason for it?

Geoff


Top
 Profile  
 
 Post subject: Re: gtk_dialog_run fails
PostPosted: Wed May 02, 2012 8:34 am 
Offline
Familiar Face

Joined: Thu Mar 29, 2012 9:40 am
Posts: 14
Hi geoffjay!! thank you for reply!!

You are right, I have to use those calls. This code works properly
Code:
#include <gtk/gtk.h>
#include <stdlib.h>
#include <pthread.h>

GtkWidget *window;

gint delete_event(GtkWidget *widget, GdkEvent *event, gpointer data )
{
    gtk_main_quit ();
    return FALSE;
}

void *thread_dialog()
{   
   gdk_threads_enter ();
   GtkWidget  *label;                               
   GtkWidget *dialog=gtk_dialog_new();
    label=gtk_label_new("just a label");
   
   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),label, TRUE, TRUE, 0);
   
   gtk_widget_show(label);
                                                 
   gtk_dialog_add_button(GTK_DIALOG(dialog),"Accept",GTK_RESPONSE_ACCEPT);
   gtk_dialog_add_button(GTK_DIALOG(dialog),"Reject",GTK_RESPONSE_REJECT);
   gint ret= gtk_dialog_run (GTK_DIALOG (dialog));                                               
   /* take action depending on ret */
   printf("value=%d\n",ret);
   gtk_widget_destroy(dialog);
   gdk_threads_leave ();
   return NULL;
}

void init_dialog()
{   
   pthread_t dialog_req;
   if(pthread_create(&dialog_req,NULL,thread_dialog,NULL)!=0)
      perror("error creating tread\n");   
}

int main( int argc, char *argv[] )
{
   g_thread_init (NULL);
   gdk_threads_init ();
   gtk_init (&argc, &argv);
    GtkWidget *button;
    GtkWidget *box1;
    gtk_rc_parse("rc_file");
      
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    g_signal_connect (G_OBJECT (window), "delete_event",G_CALLBACK (delete_event), NULL);
   
    box1 = gtk_hbox_new (FALSE, 0);
    gtk_container_add (GTK_CONTAINER (window), box1);
    button = gtk_button_new_with_label ("Button 1");
    g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (init_dialog), (gpointer) "button 1");
    gtk_box_pack_start (GTK_BOX(box1), button, TRUE, TRUE, 0);
    gtk_widget_set_name (button, "special button");
    gtk_widget_show (button);
    gtk_widget_show (box1);
    gtk_widget_show (window);
   
   gdk_threads_enter ();
   gtk_main ();
   gdk_threads_leave ();

    return 0;
}

This is a summary of a much larger code. I only wanted to post the problem, not the entire code.

I am developing a network application. So a server must be listening using “accept” call, which blocks, so that's why I need another thread. The main thread for the main application, other thread listening on clients to “connect”. When a connection from a client arrives, a dialog is shown, using gtk_dialog_run (GTK_DIALOG (dialog));

So my problem now is that if I use a server thread, it is always running, will never call to gdk_threads_leave. This is a pseudo code example
Code:
gdk_threads_enter();

while(1)
{
   accept_connections_from_client
}
gdk_threads_leave(); will never be executed

So right now the only solution is to wrap gtk_dialog_run (GTK_DIALOG (dialog)); with these calls.

Code:
gdk_threads_enter();
gtk_dialog_run (GTK_DIALOG (dialog));
gdk_threads_leave();

Do you find other solution??
Thank you very very much!!!!


Top
 Profile  
 
 Post subject: Re: gtk_dialog_run fails
PostPosted: Thu May 03, 2012 7:32 am 
Offline
Never Seen the Sunlight

Joined: Mon Apr 28, 2008 5:52 am
Posts: 709
Location: UK
Hi,

I can see many mistakes with your code.

- You have created a multi-thread application that only is allowed to use one thread at a time due to locking. And you must use locking because GTK+/GDK and X11 are not thread safe.

- The use of gdk_threads_enter() and gdk_threads_leave() is expected to be deprecated soon in the GTK+ 3 series and removed in GTK+ 4. So try not to depend on it, mainly for the previous reason and also it can make your code slower and harder to read/keep bug free.

- If you must use threads keep all code that deals with the GUI in one thread and have other threads do background work. When the background threads need to they can then communicate their data in a thread safe manner to the GUI thread. Use locks for all shared data, but the use of locks should be kept to a minimum as they then block the running of a thread.

- You are using some features that have been deprecated for a long time now. If you tell us which version of GTK+ you are using then better a answers can be given.

From what little information that you have given you may not require the use of threads. As a note you can monitor files, pipes and sockets using the "GTK main loop" see the man page at http://developer.gnome.org/glib/stable/glib-IO-Channels.html. This then allows you to connect call back functions to the signals and react in a non-blocking way. Without the need for you to explicitly use threads.

_________________
E.


Top
 Profile  
 
 Post subject: Re: gtk_dialog_run fails
PostPosted: Thu May 03, 2012 8:04 am 
Offline
Familiar Face

Joined: Thu Mar 29, 2012 9:40 am
Posts: 14
Hi errol!!
Thank you very much, you have been very helpful.

I am using gtk+-2.0.

I see what you mean, you mean that using theses calls:
pthread_mutex_lock(mutex);
pthread_mutex_unlock(mutex);

it would be much better.

I have seen the link you post about glib, and seems I have to study it very careful, but it does not have a tutorial. I am following the GTK+ tutorial on internet, but the link you have post is ok. The subjects related with glib threads are very helpful and easy, but the ones related with sockets.......

Anyway thank you very very much!!!


Top
 Profile  
 
 Post subject: Re: gtk_dialog_run fails
PostPosted: Thu May 03, 2012 9:53 am 
Offline
Familiar Face

Joined: Thu Mar 29, 2012 9:40 am
Posts: 14
Hello again!!!

I have been surfing on glibs threads, quite similar to Linux threads.... but I have one question.

Is there a similar function on glibs for pthread_cancel(thread_t t)?

Sometimes, the main thread needs to cancel or destroy another thread (not the server thread).
thank you very much!


Top
 Profile  
 
 Post subject: Re: gtk_dialog_run fails
PostPosted: Thu May 03, 2012 10:57 am 
Offline
Never Seen the Sunlight

Joined: Mon Apr 28, 2008 5:52 am
Posts: 709
Location: UK
There are sometime like 13 versions of the GTK+ version 2 series, if you exclude the bug fix versions and development ones.

Use
Code:
pkg-config --modversion gtk+-2.0
on a command line to find out the exact version.

You are confusing POSIX threads with Linux threads. They are not the same and work in very different ways. If your system is very old and you have a choice prefer to use POSIX threads.

No there is not a wrapper to pthread_cancel() in the GLib library so you will need to use POSIX threads if you need this feature. Note that you will need to add extra checks in your code to make sure that proper clean up is done otherwise you may end up with memory leaks and other bugs.

Note in the future you will only be able to call GTK+ from one thread, and no way around that. Not even the use of pthread_mutex_lock(mutex);
pthread_mutex_unlock(mutex);
will help.

Take another read of the link to the file monitoring documentation. It is very simple and I think you could hook up a call back function to your socket using just two function calls.

I have a few rules about threads.
1 Avoid
2 Only use it if they are doing processing that would take more than about 0.1 seconds.
3 Avoid blocking IO. For example the thread will go to sleep waiting for IO on a socket. This can be converted from blocking to non-blocking and the use of a thread can then be avoided.

Note within the GTK+ main loop it uses the system call select() which is a powerful call. It can wait on several IO channels and perform time-outs all within the one call. If you use this built in power then you can avoid the resource wast-full addition of threads, when all it is doing is waiting for a bit of IO on a socket. Only use threads when you have a user interface to be kept responsive and have some processor intensive task to do at the same time. And if you do use threads make sure everything is done in a thread safe way.

_________________
E.


Top
 Profile  
 
 Post subject: Re: gtk_dialog_run fails
PostPosted: Thu May 03, 2012 11:39 am 
Offline
Familiar Face

Joined: Thu Mar 29, 2012 9:40 am
Posts: 14
Hi errol thank you very much!

The output of your command is: 2.24.6

errol wrote:
Note in the future you will only be able to call GTK+ from one thread, and no way around that.


You are meaning that I will not be able to call gtk_widget_show(label_widget) from another thread apart of the main thread??

Well, I will take a look on create sockets with glib. You are right, it can be very helpful!!!

But this code is still not correct

Code:
#include <gtk/gtk.h>
#include <stdlib.h>
#include <pthread.h>

GtkWidget *window;

gint delete_event(GtkWidget *widget, GdkEvent *event, gpointer data)
{
    gtk_main_quit ();
    return FALSE;
}

void *thread_dialog()

   GtkWidget  *label;                               
   GtkWidget *dialog=gtk_dialog_new();
    label=gtk_label_new("just a label");
   
   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),label, TRUE, TRUE, 0);
   
   gtk_widget_show(label);
                                                 
   gtk_dialog_add_button(GTK_DIALOG(dialog),"Accept",GTK_RESPONSE_ACCEPT);
   gtk_dialog_add_button(GTK_DIALOG(dialog),"Reject",GTK_RESPONSE_REJECT);
   gint ret= gtk_dialog_run (GTK_DIALOG (dialog));                                               
   /* take action depending on ret */
   printf("value=%d\n",ret);
   gtk_widget_destroy(dialog);
   
   return NULL;
}

void init_dialog()
{
   g_thread_create(thread_dialog,NULL,TRUE,NULL);
}

int main( int   argc,
          char *argv[] )
{
   g_thread_init (NULL);
   gdk_threads_init ();
   gtk_init (&argc, &argv);
    GtkWidget *button;
    GtkWidget *box1;
    gtk_rc_parse("rc_file");   
   
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    g_signal_connect (G_OBJECT (window), "delete_event",G_CALLBACK (delete_event), NULL);
   
    box1 = gtk_hbox_new (FALSE, 0);
    gtk_container_add (GTK_CONTAINER (window), box1);
    button = gtk_button_new_with_label ("Button 1");
    g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (init_dialog), (gpointer) "button 1");
    gtk_box_pack_start (GTK_BOX(box1), button, TRUE, TRUE, 0);
    gtk_widget_set_name (button, "special button");
    gtk_widget_show (button);
    gtk_widget_show (box1);
    gtk_widget_show (window);   
   
   gtk_main ();
    return 0;
}


Thank you very much


Top
 Profile  
 
 Post subject: Re: gtk_dialog_run fails
PostPosted: Fri May 04, 2012 3:59 am 
Offline
Familiar Face

Joined: Tue Aug 18, 2009 5:02 pm
Posts: 23
Location: Vancouver, B.C.
To avoid a blocking accept, you should look into using select or epoll. Both of those will allow you to make your listening socket descriptor non-blocking and then just sit and wait for events to happen on it. Doing so will allow you to use gtk callbacks to generate the dialog, which is from my experience easier and safer. If you need to update some widget I agree with errol that you want to avoid doing so in a thread, what I try to do is use a mutex in a thread to lock the data while it's being updated, and then use that same data from a timer callback that gets launched along with the dialog/window that contains the widget to update.


Top
 Profile  
 
 Post subject: Re: gtk_dialog_run fails
PostPosted: Sat May 05, 2012 9:22 am 
Offline
Familiar Face

Joined: Thu Mar 29, 2012 9:40 am
Posts: 14
Hi geoffjay!! thank you very much! I understand what you mean but I have a few questions.

geoffjay wrote:
To avoid a blocking accept, you should look into using select or epoll. Both of those will allow you to make your listening socket descriptor non-blocking and then just sit and wait for events to happen on it.


I have been reading about select and Non-blocking I/O. As you say, select is a blocking call, so if I use select, I will be blocked and need to use a thread. Reading more about I/O, another solution would be Signal driven I/O, but they have recommended me that signals can get lost, signal handlers operate in strange context and shouldn't do very much.....

geoffjay wrote:
If you need to update some widget I agree with errol that you want to avoid doing so in a thread, what I try to do is use a mutex in a thread to lock the data while it's being updated, and then use that same data from a timer callback that gets launched along with the dialog/window that contains the widget to update


I have not understood you very well. What do you mean with a timer callback??

I know that you all would have expressed very clear yourself, it is my fault for so stupid questions.

Thank you very very much


Top
 Profile  
 
 Post subject: Re: gtk_dialog_run fails
PostPosted: Sat May 05, 2012 10:55 pm 
Offline
Familiar Face

Joined: Tue Aug 18, 2009 5:02 pm
Posts: 23
Location: Vancouver, B.C.
Hi jessPHP,

Being as you're developing a GTK application you should have already launched gtk_main which means you must have a separate thread to read data off of your socket anyhow no? As for using signals to perform I/O, I wouldn't do that personally, especially not when very good facilities like select/epoll/poll/kevent exist.

Here's how I would lay it out (very roughly):

Code:
main
  setup data
  create a timeout that checks for new clients and launches dialogs as needed
  launch pthread/gthread for managing client communication
  launch gtk main loop

thread
  setup listening socket
  add socket to fd set
  make socket non blocking
  loop while thread is enabled
    execute select call (with or without timeout, that's up to you)
    if listening fd is set
      create new client data and add it to a "pending clients" queue
    else if client fd is set
      read new data from socket
    else continue

client timeout callback
  loop while "pending clients" queue is > 0
    run a new dialog for the client


This may not be the best way to do it as there is an inherent delay while you're waiting for the next timeout, I'm pretty sure that you can attach a callback to a GQueue as an alternative to a timeout but I didn't feel like looking into how to do that.

To setup the timeout you need a function, eg.:
Code:
gboolean
pending_client_timeout_cb (gpointer data)
{
    /* code to execute */
    return true;
}


which you setup by:
Code:
/* execute timeout callback every 100ms */
g_timeout_add (100, (GSourceFunc)pending_client_timeout_cb, NULL);


Top
 Profile  
 
 Post subject: Re: gtk_dialog_run fails
PostPosted: Sun May 06, 2012 9:54 am 
Offline
Familiar Face

Joined: Thu Mar 29, 2012 9:40 am
Posts: 14
Hi geoffay!! thanks a lot! I understood what you meant, the use of g_timeout_add (time, call_back) but in the context of the main thread, so I can update the widget from the main thread.

But now I have other problem again with the gtk_dialog_run, because it blocks when called from the call_back, unless I use again gdk_threads_enter and gdk_threads_leave, but you said I should not use gdk_threads_enter and leave.

This is the new example:
Code:
#include <gtk/gtk.h>
#include <stdlib.h>
#include <glib.h>
#include <pthread.h>

GtkWidget *window;

gint delete_event( GtkWidget *widget,
                   GdkEvent  *event,
                   gpointer   data )
{
    gtk_main_quit ();
    return FALSE;
}

gboolean init_dialog()
{   
   //gdk_threads_enter (); //if I do not comment this, it works!!
   GtkWidget  *label;                               
   GtkWidget *dialog=gtk_dialog_new();
    label=gtk_label_new("just a label");
   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),label, TRUE, TRUE, 0);
   gtk_widget_show(label);
   gtk_dialog_add_button(GTK_DIALOG(dialog),"Accept",GTK_RESPONSE_ACCEPT);
   gtk_dialog_add_button(GTK_DIALOG(dialog),"Reject",GTK_RESPONSE_REJECT);
   gint ret= gtk_dialog_run (GTK_DIALOG (dialog));                                               
   /* take action depending on ret */
   printf("value=%d\n",ret);
   gtk_widget_destroy(dialog);
   //gdk_threads_leave ();
   return TRUE;   
}

int main(int   argc, char *argv[])
{
   g_thread_init (NULL);
   gdk_threads_init ();
   gtk_init (&argc, &argv);
    GtkWidget *button;
    GtkWidget *box1;
 
    g_timeout_add (1000,init_dialog,NULL);
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    g_signal_connect (G_OBJECT (window), "delete_event",G_CALLBACK (delete_event), NULL);
   
    box1 = gtk_hbox_new (FALSE, 0);
    gtk_container_add (GTK_CONTAINER (window), box1);
    button = gtk_button_new_with_label ("Button 1");
    g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (init_dialog), (gpointer) "button 1");
    gtk_box_pack_start (GTK_BOX(box1), button, TRUE, TRUE, 0);
    gtk_widget_show (button);
    gtk_widget_show (box1);
    gtk_widget_show (window);
   
    //gdk_threads_enter ();
   gtk_main ();
   //gdk_threads_leave ();
    return 0;
}


So what's happening now??

Thank you very much!


Top
 Profile  
 
 Post subject: Re: gtk_dialog_run fails
PostPosted: Tue May 08, 2012 8:01 am 
Offline
Familiar Face

Joined: Thu Mar 29, 2012 9:40 am
Posts: 14
Have you got any idea??


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 13 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 3 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group