zen
zen

Reputation: 31

gtk_label_set_text() segmentation fault

Here is my code.

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

#define MAX_LENGTH 8
#define WIDGET_NUM 3

typedef struct Widget
{
    GtkWidget *window;
    GtkWidget *button[WIDGET_NUM];
    GtkWidget *entry[WIDGET_NUM];
    GtkWidget *label[WIDGET_NUM];
    GtkWidget *grid;
    pthread_t pid[WIDGET_NUM];
    int button_num;
}Widget;

void num_2_time(int num, char *buf)
{
    int h = num / 3600;
    int m = num % 3600 / 60;
    int s = num % 60;

    sprintf(buf, "%d:%d:%d", h, m, s);
}

void *wait_4_waking(void *arg)
{
    Widget *window = (Widget*)arg;
    int input_num, window_num = window->button_num;
    const char *text;
    char buf[MAX_LENGTH * 2];

    text = gtk_entry_get_text(GTK_ENTRY(window->entry[window_num]));
    input_num = atoi(text);
    gtk_entry_set_text(GTK_ENTRY(window->entry[window_num]), "");

    while (input_num >= 0)
    {
        num_2_time(input_num, buf);
        //Segmentation fault
        gtk_label_set_text(GTK_LABEL(window->label[window_num]), buf);
        sleep(1);
        input_num--;
    }

    return NULL;
}

void button_clicked_0(GtkWidget *widget, gpointer data)
{
    Widget *window = (Widget*)data;
    window->button_num = 0;

    printf("%u\n", window->pid[0]);
    if (window->pid[0] > 0)
    {
        pthread_cancel(window->pid[0]);
    }
    pthread_create(window->pid, NULL, wait_4_waking, data);
}
void button_clicked_1(GtkWidget *widget, gpointer data)
{
    Widget *window = (Widget*)data;
    window->button_num = 1;

    if (window->pid[1] > 0)
    {
        pthread_cancel(window->pid[1]);
    }
    pthread_create(window->pid+1, NULL, wait_4_waking, data);
}
void button_clicked_2(GtkWidget *widget, gpointer data)
{
    Widget *window = (Widget*)data;
    window->button_num = 2;

    if (window->pid[2] > 0)
    {
        pthread_cancel(window->pid[2]);
    }
    pthread_create(window->pid+2, NULL, wait_4_waking, data);
}


int main (int argc, char **argv)
{
    Widget window;
    int i;
    void (*button_clicked[WIDGET_NUM])(GtkWidget*, gpointer) = {
        button_clicked_0, button_clicked_1, button_clicked_2
    };

    gtk_init(&argc, &argv);

    window.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title (GTK_WINDOW (window.window), "Window");
    gtk_window_set_default_size (GTK_WINDOW (window.window), 400, 200);

    window.grid = gtk_grid_new();
    for (i = 0; i < WIDGET_NUM; i++)
    {
        window.entry[i] = gtk_entry_new();
        window.label[i] = gtk_label_new("0:0:0");
        window.button[i] = gtk_button_new_with_label("Go!");
        window.pid[i] = 0;
        gtk_entry_set_max_length(GTK_ENTRY(window.entry[i]), MAX_LENGTH);
        gtk_grid_attach(GTK_GRID(window.grid), window.entry[i], 0, i, 1, 1);
        gtk_grid_attach(GTK_GRID(window.grid), window.button[i], 1, i, 1, 1);
        gtk_grid_attach(GTK_GRID(window.grid), window.label[i], 2, i, 1, 1);
    }
    gtk_container_add (GTK_CONTAINER (window.window), window.grid);

    for (i = 0; i < WIDGET_NUM; i++)
    {
        g_signal_connect (window.button[i], "clicked", G_CALLBACK (button_clicked[i]), (gpointer)&window);
    }

    g_signal_connect (window.window, "destroy", G_CALLBACK(gtk_main_quit), NULL);

    gtk_widget_show_all (window.window);
    gtk_main();

    return 0;
}

Building command:

gcc -o 1 test2.c `pkg-config --libs --cflags gtk+-3.0` -pthread -g


This error occurred when I clicked The button, but it didn't occur all the time.
Before it occurred, I get an information below.
(1:18144): Pango-CRITICAL **: pango_layout_get_pixel_extents: assertion 'PANGO_IS_LAYOUT (layout)' failed (1:18144): Pango-CRITICAL **: pango_layout_get_iter: assertion 'PANGO_IS_LAYOUT (layout)' failed
And then segmentation fault.

I checked its information by dmesg command. And I got this.
[ 703.437988] 1[6358]: segfault at 10 ip 00007f9b07ac3f91 sp 00007ffe3bd53790 error 4 in libpango-1.0.so.0.3800.1[7f9b07aa0000+48000]

How can I do for this error?

Upvotes: 0

Views: 842

Answers (1)

Jussi Kukkonen
Jussi Kukkonen

Reputation: 14607

You are calling a Gtk+ widget function from another thread. Gtk+ is not thread safe so don't do that.

Your best option is to avoid threads: design your code so that the main loop is never blocked for long periods. Usually when I see threading problems, the use of threads is unnecessary and the whole mess could have been avoided by a cleaner design.

If the code can't be designed in a better way, then you'll need to use e.g. g_main_context_invoke() in your other thread to invoke a function in the main thread: that function can then modify the Gtk+ widget state safely. Be careful not to make mistakes with lifetimes of pointers that you share between threads.

Upvotes: 2

Related Questions