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 Oct 31, 2014 9:09 am

All times are UTC




Post new topic Reply to topic  [ 6 posts ] 
Author Message
 Post subject: GTK+ Multithreading related question
PostPosted: Tue Nov 15, 2011 8:05 am 
Offline
Familiar Face

Joined: Tue Nov 15, 2011 7:45 am
Posts: 5
Hello all,

I am new to GTK+ and hence I am going to ask you the experts one of my issue that I am kind of hit the wall...

I am designing an application that deals with an analog (telephoney Modem). The idea is when the user clicks on a button the modem will dial a specific number and reads a remote user input from the telephone keypress. Also, there is a hangup button that users could push to end the call at any time.

My issue is, I start dialing the phone number and the rest of the GUI is all blocked. so I have introduced two threads invoked by button clicks, one for dialing and the other for hanging up the line.

Code:
  1 #include <all-required-headers.h>
  2
  3 GtkWidget* button;
  4 GtkWidget* button1;
  5 pthread_t a_thread;
  6 pthread_t b_thread;
  7 pthread_mutex_t mutex;
  8
  9 int modem_fd;
10
11 void* threadfunc_dial(void* arg);
12 void* threadfunc_hangup(void* arg);
13
14 void destroy(GtkWidget* widget, gpointer data)
15 {
16     gtk_main_quit();
17 }
18
19 void* threadfunc_dial(void* arg)
20 {
21     pthread_mutex_lock(&mutex);
22     printf("threadfunc_call: dialing modem now..\n");
23
24     gdk_threads_enter();
25     dial_number("4164161234"); // phone to dial out
26     gdk_threads_leave();
27
28     pthread_mutex_unlock(&mutex);
29     return NULL;
30 }
31
32 void* threadfunc_hangup(void* arg)
33 {
34     pthread_mutex_lock(&mutex);
35     printf("threadfunc_call: dialing modem now..\n");
36
37     gdk_threads_enter();
38     write_port("ATH",modem_fd);
39     gdk_threads_leave();
40
41     pthread_mutex_unlock(&mutex);
42     return NULL;
43 }
44
45 void buttonclicked(GtkWidget* widget, gpointer data)
46 {
47     int res;
48     printf("starting DIAL thread ..\n");
49     res = pthread_create(&a_thread, NULL, threadfunc_dial, NULL);
50     if(res != 0)
51     {
52         perror("thread creation failed");
53         exit(-1);
54     }
55 }
56
57 void buttonclicked1(GtkWidget* widget, gpointer data)
58 {
59     int res;
60     printf("starting HANGUP thread ..\n");
61     res = pthread_create(&b_thread, NULL, threadfunc_hangup, NULL);
62     if(res != 0)
63     {
64         perror("thread creation failed");
65         exit(-1);
66     }
67 }
68
69 int main(int argc, char* argv[])
70 {
71     if (!g_thread_supported ()){ g_thread_init(NULL); }
72     gdk_threads_init();
73     gdk_threads_enter();
74     gtk_init(&argc, &argv);
75
76     GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
77     gtk_signal_connect(GTK_OBJECT (window), "destroy",
78     GTK_SIGNAL_FUNC(destroy), NULL);
79
80     gtk_container_set_border_width(GTK_CONTAINER (window), 10);
81
82     /* add a button to do something usefull */
83     GtkWidget* vbox1 = gtk_vbox_new( 0, 2);
84     button = gtk_button_new_with_label("Dial Phone");
85     button1 = gtk_button_new_with_label("Hangup Phone 1");
86
87     gtk_signal_connect(GTK_OBJECT (button),"clicked",GTK_SIGNAL_FUNC(buttonclicked), NULL);
88     gtk_signal_connect(GTK_OBJECT (button1),"clicked",GTK_SIGNAL_FUNC(buttonclicked1), NULL);
89
90     gtk_container_add(GTK_CONTAINER(window), vbox1);
91     gtk_container_add(GTK_CONTAINER(vbox1), button);
92     gtk_container_add(GTK_CONTAINER(vbox1), button1);
93
94     /* show everything */
95     gtk_widget_show_all(window);
96
97     /* main loop */
98     gtk_main ();
99     gdk_threads_leave();
100
101     return 0;
102 }
103
104 int write_port()
105 {
106     // this function write data to the serial port
107 }
108
109 int read_port(int fd, unsigned char *result)
110 {
111     // this function will read the data from the serial port
112 }
113
114 int dtmf_detection( char *res)
115 {
116     // this function will decode the DTMF signals
117 }
118
119 // this function will dial the provided number
120 int dial_number(char *number)
121 {
122
123     write_port(number);
124     read_port();
125     dtmf_detection();
126     return 0;
127 }


Please let me know what/where I am making the mistake. I have looked at few different examples and put together this test. I have tested all my modem related code in separate unit tests.

Thank you so much for your helps!!!

Nikke


Top
 Profile  
 
 Post subject: Re: GTK+ Multithreading related question
PostPosted: Thu Nov 17, 2011 12:36 am 
Offline
Familiar Face

Joined: Tue Nov 15, 2011 7:45 am
Posts: 5
Hello experts! No one here to answer my question about threading :) I am not sure if there is another place where I need to post my question, if so please do let me know.

Thanks!

Nikke.


Top
 Profile  
 
 Post subject: Re: GTK+ Multithreading related question
PostPosted: Thu Nov 17, 2011 7:40 am 
Offline
Never Seen the Sunlight

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

You have not stated which version of GTK+ you are using. I assume that it is version 2.xx or even version 1.xx. You are now using functions that have long be deprecated and now removed in GTK+ version 3.xx.

I can also see problems with your multi-threading code which can cause problems, such as locking your GUI if the reading or writing to the serial port takes a long time or blocks. This is due to the incorrect use of locks and you do not seam to have a method of communicating between threads.

If you can let us know what version of GTK+ you are using and what system it is targeted for then I can come up with a more detailed solutions.

_________________
E.


Top
 Profile  
 
 Post subject: Re: GTK+ Multithreading related question
PostPosted: Thu Nov 17, 2011 5:40 pm 
Offline
Familiar Face

Joined: Tue Nov 15, 2011 7:45 am
Posts: 5
Hi Errol, thanks for your post. I am planning on running this on a Ubutu 11.04 machine which has Gtk version 2.24.4.

Also, at this point I don't need any communication between the threads. The idea I had was to invoke a thread every time the modem dial-out is required. If I could save the save the serial port's open file handle to a global variable, I could use that with another thread to terminate/close the serial port communication.

sudo code....

main GUI code
{

initialize/invoke all GUI widgets including the dial_out & hangup buttons.

if dial_out button is pressed, invoke a new thread, save the open file handle to the global variable, start serving the modem.

if hangup button is pressed, invoke a new thread, send the "ATH" command to the modem and close the serial port (if possible kill the other thread as well)

}

I wish to use the later version of the GTK, but we have done some design based on the version of Glade that came with Ubuntu 11.04.

Please be kind enough to let me know what mistakes I am making and what/how could I do to my code to make this wok the way I have planned. If not please let me know of any other better way to do this task. Your help is much appreciated.

Thanks,

Nikke


Top
 Profile  
 
 Post subject: Re: GTK+ Multithreading related question
PostPosted: Fri Nov 18, 2011 9:25 am 
Offline
Never Seen the Sunlight

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

I will start with the deprecated function that you have used and which has now been removed from version 3 of GTK. You have used the function gtk_signal_connect() which has now been replace with g_signal_connect(). So for example on line 87 you would use.
Code:
    g_signal_connect(button, "clicked" , G_CALLBACK(buttonclicked), NULL);


On lines 24, 26, 37 and 39 you have used the functions gdk_threads_enter() and gdk_threads_leave() (the GDK lock). These functions lock and unlock the internals of GDK/GTK so that only one thread at a time can access it (which is what is needed). But in your example code you have written a single threaded application using threads in a complex way. So if dial_number() takes a long time and waits, then you GUI will also be locked out. If dial_number() and write_port() do not call any GDK/GTK functions then the use of GDK lock is not needed.

Now that we are hopefully running multi threaded, the next thing to watch out for is the so called "Heisenbugs". One thing that could be a problem is if the user pressed the "Dial Phone" button and did not get a response because the thread is still running and presses it again, you now have two threads doing a dial phone, one waiting while the first is still running! So proper communication is needed.

You may with a bit of care be able to write much of you code using a single thread and have the GTK main loop do the monitoring of the modem_fd. This may only be useful if it is set to non-blocking.

You could also try having two threads. Your main thread that has GUI stuff, then your modem thread which waits for commands from the main thread and sends back responses. This would avoid the over head of creating and destroying a thread for each button press. And only delegate long processing stuff to a new thread.

Hope this helps.

E.

_________________
E.


Top
 Profile  
 
 Post subject: SOLVED: GTK+ Multithreading related question
PostPosted: Fri Nov 18, 2011 6:00 pm 
Offline
Familiar Face

Joined: Tue Nov 15, 2011 7:45 am
Posts: 5
Hi Errol,

Thanks for the prompt answer and you have made my brain think! It takes a bit of beating before that happens :)
I have decided to go with your last option and in minutes I was able to acheive what I was after. The modem part still needs some tweaks but that has nothing to do with this anyways.

errol wrote:
You could also try having two threads. Your main thread that has GUI stuff, then your modem thread which waits for commands from the main thread and sends back responses. This would avoid the over head of creating and destroying a thread for each button press. And only delegate long processing stuff to a new thread.


Now I am starting a thread that initialize the modem and waits for my commands. The commands are initiated by the button clicks and getting pushed to a command queue variable. If there is a command to be executed the modem thread will jump in and execute the command! I think it can't any more cleaner than what I have! (at least in my case!), I am sure you experts will have thousand other ways of improving it!

Again, thanks for your help! Please keep up the good work!

Nikke.


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

All times are UTC


Who is online

Users browsing this forum: Google [Bot] and 1 guest


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