Still confused on new thread starting idle functions to update UI.
- From: David Buchan <pdbuchan yahoo com>
- To: gtk-app-devel-list list <gtk-app-devel-list gnome org>
- Subject: Still confused on new thread starting idle functions to update UI.
- Date: Tue, 3 Dec 2013 11:02:53 -0800 (PST)
These darn threads and idle functions still baffle me. I'm sorry to be such a pest.
I want to periodically update a textview as new information comes available. Sometimes this information can
come in quickly (roughly every tenth of a second). Each update is a single line of text.
The observed bad behavior is that sometimes messages don't appear at all, or appear twice in my textview.
It's quite unpredictable. Sounds like a race condition.
I spawn a thread from the main program - and from now on I don't talk about main - and this new thread
prepares messages in a character string. The thread then passes a pointer to the character string to an idle
function so that the idle function can update a textview in the UI. When done, the idle function stops itself
by returning a G_SOURCE_REMOVE boolean.
The thread allocates memory for the character string, and the idle function does not free it. Instead, the
thread free's the memory just before it stops. It waits a bit to make sure the idle function has finished
using the memory containing the message.
But I lied...
Because there are several messages (roughly 30), the thread actually allocates memory for an *array* of
character strings. An index is then used to specify which one we're using.
This may seem awkward and unnecessary, but if I just use a single character string, it is possible for the
thread to replace the contents of the string with the next message while an idle function is still working
with the previous message.
So instead I rotate through 30 character strings with the assumption that by the time the 30th idle function
is finished, the character string at index 0 is no longer being used by the first idle function and that
string can now be re-used.
What I had before which worked was a single character string and a sleep (1) after each g_idle_add(), but
that made things very sluggish.
In the header file, I have:
****** code snip ******
// Define a struct to contain pointers to textview and message for post_message().
typedef struct _msgdata msgdata;
struct _msgdata {
char *message;
GtkWidget *textview;
};
#define MAXBUF 30
****** end code snip ******
In my thread (not main), I have:
****** code snip ******
int i, indx;
msgdata *msgdata;
msgdata = (msgdata *) malloc (MAXBUF * sizeof (msgdata));
memset (msgdata, 0, MAXBUF * sizeof (msgdata));
for (i=0; i<MAXBUF; i++) {
msgdata[i].message = (char *) malloc (1024 * sizeof (char));
memset (msgdata[i].message, 0, 1024 * sizeof (char));
}
indx = 0;
for loop {
Do interesting things.
// Report latest results.
sprintf (msgdata[indx].message, "Some interesting messages %s %i %f etc\n", various arguments);
msgdata[indx].textview = data->textview1;
g_idle_add ((GSourceFunc) post_message, &msgdata[indx]);
next_msg(&indx);
if (we're done) break;
}
sleep (1); // Wait for idle functions to finish using character string memory.
for (i=0; i<MAXBUF; i++) {
free (msgdata[i].message);
}
free (msgdata);
return (EXIT_SUCCESS);
****** end code snip ******
The ugly helper function which increments the index is:
****** code ******
// Increment message buffer index.
int
next_msg (int *index)
{
index++;
if ((*index) > (MAXBUF - 1)) {
(*index) = 0;
}
return (EXIT_SUCCESS);
}
****** end code ******
And the idle function:
****** code ******
// Idle function to add a message to a textview.
// This idle function returns 0 in order to stop.
gboolean
post_message (msgdata *data)
{
GtkTextBuffer *textbuffer;
GtkTextIter end;
textbuffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (data->textview));
gtk_text_buffer_get_end_iter (textbuffer, &end);
gtk_text_buffer_insert (textbuffer, &end, data->message, -1);
gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (data->textview), &end, 0.0, FALSE, 0, 0);
return (G_SOURCE_REMOVE); // This idle function stops when it returns G_SOURCE_REMOVE.
}
****** end code ******
I would've liked to pass the message string to the idle function by value, because then it would only work
with its own ephemeral copy of the string, but g_idle_add() only allows me to pass a pointer to data, not the
data itself.
As always, any advice is appreciated,
Dave
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]