GLib GMainContext in a thread?

一笑奈何 提交于 2019-12-11 04:27:21

问题


I have searched on stack overflow to find answer relevant to my problem. But i didn't find any answer.

I have a main thread (my main() function) which starts a thread. The new thread runs GMainLoop. In my main function, i keep adding sources by calling g_io_watch over some file descriptors. But i have getting garbage data if events are dispatched.

Below is a small part of the code that i am trying:

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;

}

However, if i try this code, then everything works as expected:

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;

} 

Edit:

I have tried passing the default GMainContext of the main thread to the newly created thread. Have a look. Tell me if my approach is correct.

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;

} 

回答1:


You need to use GMainContext if you want to run a main loop from a thread. From the Glib's 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.

When you create a main loop with g_main_loop_new(NULL, FALSE);, while it's handy to not specify any GMainContext, you need to pass a GMainContext from which you want your loop if you want to run the loop in a different thread. You can create a GMainContext with g_main_context_new() and pass it to g_main_loop_new(), or use g_main_context_get_thread_default() to get the default main context for the running thread.

g_io_add_watch() is yet another handy version of the function, which

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

Unfortunately, there is no g_io_add_watch() variant function to specify a main context, you have to manually create a GSource from your GIOChannel, p_hci_io, and attach to your context via g_source_attach(). Note that g_io_add_watch_full() also works with the default main context.

The reason your second code works is that you created your main loop in the main thread which has your source attached.



来源:https://stackoverflow.com/questions/42395844/glib-gmaincontext-in-a-thread

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!