从线程调用时,GTK 代码挂起@gtk_container_add
Posted
技术标签:
【中文标题】从线程调用时,GTK 代码挂起@gtk_container_add【英文标题】:GTK code hangs @ gtk_container_add when called from thread 【发布时间】:2013-08-28 06:35:44 【问题描述】:我是 GTK 和 GLIB 的新手 我只是想显示一个图像,然后调用一个 disptext 函数。 但是当直接从 main 调用 disptextpage 函数时它可以工作但是当我创建一个线程可以调用 disptextpage 它卡在
gtk_container_add(GTK_CONTAINER(window), textv);
永远不会回来。 我犯了什么错误
请指导:下面是示例代码:
#include <stdio.h>
#include <glib.h>
#include <gtk/gtk.h>
//#include "dispimage.h"
#include <windows.h>
#define sleep(n) Sleep(1000 * n)
GtkWidget* window;
void dispInit(int argc, char* argv[]);
void dispInfoPage(char* fileName, int duration);
gpointer main_callback(gpointer data)
gtk_main();
return 0;
void dispInit(int argc, char* argv[])
gdk_threads_init();
gdk_threads_enter();
printf("Initializing the display library\n");
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_resize(GTK_WINDOW(window), 640, 480);
gtk_window_set_default_size(GTK_WINDOW(window), 640, 480);
gtk_widget_realize( window );
gtk_window_set_decorated(GTK_WINDOW(window), FALSE);
g_thread_create(main_callback, NULL, FALSE, NULL);
gdk_threads_leave();
void dispInfoPage(char* fileName, int duration)
int index;
gdk_threads_enter();
printf("Initializing dispInfoPage\n");
destroyWidget();
printf("Initializing dispInfoPage1\n");
GtkWidget *image;
image = gtk_image_new_from_file(fileName);
printf("Initializing dispInfoPage2\n");
gtk_container_add(GTK_CONTAINER(window), image);
gtk_widget_show(image);
gtk_widget_show(window);
printf("Initializing dispInfoPage4\n");
printf("Initializing dispInfoPage5\n");
gdk_threads_leave();
printf("Initializing dispInfoPage6\n");
void destroyWidget()
GList *children, *iter;
struct WidgetsAlive *temp, *prev, *next, *depTemp;
children = gtk_container_get_children(GTK_CONTAINER(window));
for(iter = children; iter != NULL; iter = g_list_next(iter))
gtk_container_remove(GTK_CONTAINER(window),GTK_WIDGET(iter->data));
printf("Deleting Widget\n");
g_list_free(iter);
g_list_free(children);
int dispTextPage(char* fileName, int isJustifyCenter)
int index;
GtkWidget *textv;
GdkWindow *textv_window;
GdkPixmap *pixmap = NULL;
GtkTextBuffer *textBuffer;
gdk_threads_enter();
GdkColor color;
char debugBuf[128] = '\0' ;
char newfName[100]='\0';
char ext[4]='\0';
char temp[100]='\0';
int i;
FILE * fd;
destroyWidget();
textBuffer = gtk_text_buffer_new(NULL);
textv = gtk_text_view_new_with_buffer(textBuffer);
gtk_text_view_set_left_margin(GTK_TEXT_VIEW(textv), 22);
gtk_text_view_set_right_margin(GTK_TEXT_VIEW(textv), 20);
gtk_text_view_set_pixels_above_lines(GTK_TEXT_VIEW(textv),1);
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(textv), GTK_WRAP_CHAR);
if (isJustifyCenter == 1)
gtk_text_view_set_justification(GTK_TEXT_VIEW(textv), GTK_JUSTIFY_CENTER);
else
gtk_text_view_set_justification(GTK_TEXT_VIEW(textv), GTK_JUSTIFY_LEFT);
gtk_text_view_set_editable(GTK_TEXT_VIEW(textv), FALSE);
gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(textv), FALSE);
printf("tttt0");
gtk_container_add(GTK_CONTAINER(window), textv);
printf("tttt1");
textv_window = gtk_text_view_get_window (GTK_TEXT_VIEW (textv),
GTK_TEXT_WINDOW_TEXT);
gdk_color_parse ("#68604d", &color);
pixmap = gdk_pixmap_create_from_xpm ((GdkDrawable *) textv_window, NULL,
&color, fileName);
gdk_window_set_back_pixmap (textv_window, pixmap, FALSE);
g_object_unref(pixmap);
textBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textv));
gtk_text_buffer_create_tag (textBuffer, "Red", "foreground", "Red", NULL);
gtk_text_buffer_create_tag (textBuffer, "RedBold","foreground", "Red",NULL);
gtk_text_buffer_create_tag(textBuffer, "gray_bg", "background", "gray", NULL);
gtk_text_buffer_create_tag(textBuffer, "italic", "style", PANGO_STYLE_ITALIC, NULL);
gtk_text_buffer_create_tag(textBuffer, "bold","weight", PANGO_WEIGHT_BOLD, NULL);
gtk_text_buffer_create_tag (textBuffer, "RedFontWeight", "weight", 1000,NULL);
gtk_text_buffer_create_tag (textBuffer, "RedBoldFontWeight","weight", 1000,NULL);
gtk_widget_show(textv);
gtk_widget_show(window);
gdk_threads_leave();
return index;
void *fsmThread_RunFunction()
int pollMsgRetVal = -1;
printf("Now enter into for image");
dispInfoPage("../images/givefp.gif",1);
sleep(5);
dispInfoPage("../images/bootup.gif",1);
sleep(5);
dispInfoPage("../images/givefp.gif",1);
sleep(5);
dispInfoPage("../images/bootup.gif",1);
sleep(5);
printf("Now enter into for disptext");
dispTextPage("",0);
printf("Now exit for disptext");
int main(int argc, char *argv[])
GThread *fsmThreadId;
GError *error = NULL;
g_thread_init(NULL);
dispInit(argc, argv);
dispInfoPage("../images/bootup.gif",1);
sleep(5);
printf("Now creat ethread ");
fsmThreadId = g_thread_create(fsmThread_RunFunction,NULL,TRUE,&error);
if (error)
fflush(stderr);
exit(1);
g_thread_join(fsmThreadId);
sleep(2);
printf("ENd of main");
return 0;
【问题讨论】:
【参考方案1】:所有 UI 操作/功能只能从一个线程调用。这是几乎所有(我所知道的)UI 库(Gtk+、Qt、wxWidgets...)的常见 API 使用要求
只是不要这样做。使用工作线程,使用g_idle_add
或g_timeout_add
并在那里进行(及时简短的)UI 修改。
【讨论】:
:跨线程之间通信的最佳方法是什么 @Ragav 他已经提到过:通常你会在非主线程中使用g_idle_add()
。
g_idle_add
与 g_async_queue_push/pop
结合使用(后者可能不需要,取决于您的问题和实现方式)
@drahnr 感谢 :: g_idle_add :: 非常有帮助,现在正在检查处理参数的最佳方式...以上是关于从线程调用时,GTK 代码挂起@gtk_container_add的主要内容,如果未能解决你的问题,请参考以下文章
如何从 GTK+2 C 代码中调用 matlab/octave 函数