2017-02-22 60 views
1

我已經搜索堆棧溢出找到與我的問題相關的答案。但我沒有找到任何答案。GLib GMainContext在一個線程中?

我有一個主線程(我的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; 

} 

回答

2

如果要從線程運行主循環,則需要使用GMainContext。從油嘴的main loop documentation

爲了允許的源的多個組獨立於 不同的線程來處理,每個源與GMainContext相關聯。 A GMainContext只能在單個線程中運行,但源可以將 添加到其中並從其他線程中刪除。

當你創建g_main_loop_new(NULL, FALSE);主循環,而這是很方便的指定任何GMainContext,你需要通過從你希望你的循環一個GMainContext如果你想運行在不同的線程循環。您可以使用g_main_context_new()創建GMainContext並將其傳遞給g_main_loop_new(),或者使用g_main_context_get_thread_default()獲取運行線程的默認主要上下文。

g_io_add_watch()又是功能的另一種方便的版本,這

添加GIOChannel與 默認優先級的默認主循環環境。

不幸的是,沒有g_io_add_watch()變異函數指定一個主背景下,你必須從手動創建GSourceGIOChannelp_hci_io,並通過g_source_attach()連接到您的上下文。請注意,g_io_add_watch_full()也適用於默認的主要上下文。

你的第二個代碼工作的原因是,你在主線程中創建了你的主循環,它有你的源代碼。

+0

我編輯了我的答案。請看編輯部分 – abhiarora

+0

「你的第二個代碼工作的原因是你用默認主環境中的循環覆蓋了全局變量循環,它有你的源代碼。」 - 我的第二個版本不覆蓋全局循環變量。我在main()函數中調用了init()函數調用。 – abhiarora

+0

感謝您的回答。我已經將主線程的GMainContext傳遞給新創建的線程。在新創建的線程中,我使用主線程的GMainContext創建主循環。我正在向全局GMainContext添加源代碼,以便在發生事件時,新線程將分派它們。我錯過了什麼嗎?你可以在你的答案中包含任何代碼嗎? – abhiarora