使用GTK解决问题

时间:2013-09-05 23:22:57

标签: c multithreading gtk pthreads gtk3

我正在使用GTK构建一个相当简单的C application,但必须执行一些阻止IO,这将触发GUI的更新。为此,我在pthread之前开始新的gtk_main()

/* global variables */
GMainContext *mainc;

/* local variables */
FILE *fifo;
pthread_t reader;

/* main() */
mainc = g_main_context_default();
pthread_create(&reader, NULL, watch_fifo, argv[argc-1]);
gtk_main();

pthread读取某些数据时,它会更新GUI,如下所示:

g_main_context_invoke(mainc, set_icon, param);

set_icon

的位置
gboolean set_icon(gpointer data)
{
    char *p = (char*)data;
    gtk_status_icon_set_from_icon_name(icon, p);
    return FALSE;
}

这一切都在大部分时间都有效,但每次我都会收到这个奇怪的错误信息:

[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.
mktrayicon: xcb_io.c:274: poll_for_event: Assertion `!xcb_xlib_threads_sequence_lost' failed.

我认为使用g_main_context_invoke的重点是避免线程问题?做了一些谷歌搜索,我遇到了gdk_threads_initgdk_threads_enter和朋友,但他们似乎都被弃用了?我知道GTK文档说所有的GUI更新都应该在主线程上执行,但这并不能很好地结合阻塞IO,我宁愿不必在线程之间构建一些复杂的通信机制。

所以,我的问题是,我该如何正确处理这个?

编辑:可以看到完整的代码here EDIT2:作为基于@ ptomato答案的更新,我已经转移到GThread并使用gdk_threads_add_idle()提交this提交,但问题仍然存在。

4 个答案:

答案 0 :(得分:10)

致电XInitThreads()。这应该在gtk_init之前完成,这将停止消息!

这样的事情:

    #include <X11/Xlib.h>
    ...  
    XInitThreads();
    ...
    gtk_init(&argc, &argv);

我不记得在GLIB 2.32之前看过这些消息 使用g_thread_init() / gdk_threads_init()

您可能需要查看g_thread_pool_newg_thread_pool_push。 从线程中,使用g_main_context_invoke在主循环或执行中执行 只需在gdk_threads_enter() / gdk_threads_leave()

之间换行

我不使用托盘,所以我不能轻易检查这个。我想你是 使用锁来纠正gdk_threads_add_idle以保护GTK / GDK API。 对我来说没有什么可以导致这些消息 出现。 gtk_status_icon_new_from_icon_name的函数说明 说明&#34;如果当前图标主题被更改,则图标将是 适当更新。对我而言,暗示您的代码不是唯一的 将访问X显示的代码,可能是 问题

还有一些关于XInitThreads()的相关信息

What is the downside of XInitThreads()?

请注意,虽然GDK使用锁定显示,但GTK / GDK不会 调用XInitThreads。

旁注:保护全局变量的内容&#34; onclick&#34;, 在fork()之后传递给execl,子节点不会继承父节点 内存锁和GLib主循环与fork()不兼容。 也许你可以将字符串复制到局部变量。

答案 1 :(得分:1)

我不确定裸pthread是否可以保证与GTK一起使用。你应该使用GThread包装器。

我认为问题可能是g_main_context_invoke()set_icon()添加为空闲功能。 (这似乎是幕后发生的事情,但我不确定。)使用GLib API添加的空闲函数尽管在主线程上执行,但需要保持GDK锁定。如果您使用gdk_threads_add_idle() API(未弃用)来调用set_icon(),那么一切都应该可以正常使用线程。

(虽然这只是一个疯狂的猜测。)

答案 2 :(得分:0)

作为一种解决方法,如果您只是想在等待某些IO时避免阻止UI,则可以使用GIO中的异步IO。这样可以避免你自己管理线程。

编辑:考虑一下你可以将你的文件描述符标记为非阻塞,并将它们作为源添加到glib主循环中,它将在主事件循环中为你轮询它们而不必乱用线程。

答案 3 :(得分:0)

您可以通过使用gio_add_watch()避免使用线程,当通道上有可用数据时,它会调用您的回调函数。