线程中的 GLib GMainContext?

GLib GMainContext in a thread?

我搜索了堆栈溢出以找到与我的问题相关的答案。但我没有找到任何答案。

我有一个启动线程的主线程(我的 main() 函数)。新线程运行 GMainLoop。在我的主要功能中,我通过对某些文件描述符调用 g_io_watch 来不断添加源。但是如果事件被调度,我会得到垃圾数据。

下面是我正在尝试的一小部分代码:

GMainLoop *loop;

gpointer event_loop_thread(gpointer arg)
{   
    g_main_loop_run(loop);
    g_main_loop_unref(loop);
    return NULL;
}

int init()
{
    loop = g_main_loop_new(NULL, FALSE);
    g_thread_new(NULL, event_loop_thread, NULL);
    return 0;
}

gboolean __hci_service(GIOChannel *source, GIOCondition condition, gpointer data)
{
    // Doing something
    return FALSE;
}

int main()
{
    init();
    int _adapter_id = hci_devid("hci0");
    int hci_dev = hci_open_dev(_adapter_id);
    GIOChannel *p_hci_io = g_io_channel_unix_new(dev_id);

    GIOCondition cond = (GIOCondition)(G_IO_IN);
    g_io_add_watch(p_hci_io, cond, __hci_service, NULL);

    while (true);
    // I will close file descriptor
    return 0;

}

但是,如果我尝试这段代码,那么一切都会按预期运行:

GMainLoop *loop;

gpointer event_loop_thread(gpointer arg)
{   
    g_main_loop_run(loop);
    g_main_loop_unref(loop);
    return NULL;
}

int init()
{
    loop = g_main_loop_new(NULL, FALSE);
    g_thread_new(NULL, event_loop_thread, NULL);
    return 0;
}

gboolean __hci_service(GIOChannel *source, GIOCondition condition, gpointer data)
{
    // Doing something
    return FALSE;
}

int main()
{
    // init();
    int _adapter_id = hci_devid("hci0");
    int hci_dev = hci_open_dev(_adapter_id);
    GIOChannel *p_hci_io = g_io_channel_unix_new(dev_id);

    GIOCondition cond = (GIOCondition)(G_IO_IN);
    g_io_add_watch(p_hci_io, cond, __hci_service, NULL);

    loop = g_main_loop_new(NULL, FALSE);
    g_main_loop_run(loop);
    g_main_loop_unref(loop);

    while (true);
    // I will close file descriptor
    return 0;

} 

编辑:

我试过将主线程的默认GMainContext传递给新创建的线程。看一看。告诉我我的方法是否正确。

GMainLoop *loop;

gpointer event_loop_thread(gpointer arg)
{   
    GMainContext *context = (GMainContext *)arg;
    loop = g_main_loop_new(context, FALSE);
    g_main_context_push_thread_default(context);
    g_main_loop_run(loop);
    g_main_loop_unref(loop);
    return NULL;
}

int init()
{

    g_thread_new(NULL, event_loop_thread, (gpointer)g_main_context_default());
    return 0;
}

gboolean __hci_service(GIOChannel *source, GIOCondition condition, gpointer data)
{
    // Doing something
    return FALSE;
}

int main()
{
    init();
    int _adapter_id = hci_devid("hci0");
    int hci_dev = hci_open_dev(_adapter_id);
    GIOChannel *p_hci_io = g_io_channel_unix_new(dev_id);

    GIOCondition cond = (GIOCondition)(G_IO_IN);
    g_io_add_watch(p_hci_io, cond, __hci_service, NULL);

    //loop = g_main_loop_new(NULL, FALSE);
    //g_main_loop_run(loop);
    //g_main_loop_unref(loop);

    while (true);
    // I will close file descriptor
    return 0;

} 

如果你想从一个线程运行一个主循环,你需要使用GMainContext。来自 Glib 的 main loop documentation:

To allow multiple independent sets of sources to be handled in different threads, each source is associated with a GMainContext. A GMainContext can only be running in a single thread, but sources can be added to it and removed from it from other threads.

当您使用 g_main_loop_new(NULL, FALSE); 创建主循环时,虽然 指定任何 GMainContext 很方便,但您需要传递一个 GMainContext,如果你想 运行 在不同的线程中循环。您可以使用 g_main_context_new() 创建一个 GMainContext 并将其传递给 g_main_loop_new(),或者使用 g_main_context_get_thread_default() 来获取 运行ning 线程的默认主上下文。

g_io_add_watch() 是该函数的另一个方便版本,

Adds the GIOChannel into the default main loop context with the default priority.

不幸的是,没有 g_io_add_watch() 变体函数来指定主上下文,您必须从 GIOChannelp_hci_io 手动创建一个 GSource,然后附加通过 g_source_attach(). Note that g_io_add_watch_full() 到您的上下文也适用于默认的主上下文。

您的第二个代码起作用的原因是您在附加了源代码的主线程中创建了主循环。