5_07_GLib库入门与实践_主循环

简介

GLib主循环用来处理GLib和GTK+应用程序的所有事件源。GTK+的事件驱动特性正是基于GLib主循环。
GLib主循环设计思想是基于poll的"prepare/check/dispatch"模式,支持多事件源,像键盘、鼠标、文件、管道、设备、套接字、定时器及其他自定义事件类型对象都可以产生事件,这些事件可以作为事件源增加到主循环被统一管理。当产生事件时,主循环会调用事件源处理函数处理该事件。
GLib主循环模块内置了Idle和Timeout两个事件源。Idle主要实现异步事件,支持重复执行,当用户注册的回调函数返回TRUE时会重复执行;Timeout用于实现定时器,支持一次定时和
重复定时,也是根据用户注册的回调函数返回值决定。
GLib有三个重要对象:GMainLoop,GMainContext和GSource。GMainloop用来处理事件循环,GSource是事件源,GMainContext将GMainloop和GSource关联起来。每个GMainloop都包含一个GMainContext对象,一个GMainContext对象可以关联多个GSource,每个GSource产生相同或不同的事件。
主循环支持多线程操作,线程可以向自己的mainloop增加Source,也可以向其他线程的mainloop增加Source。要特别注意的是向其他线程的mainloop增加Source时,对方线程可能正挂在poll中,此时需要将其唤醒,否则Source可能来不及处理。g_main_context_wakeup可以唤醒一个正在睡眠的mainloop线程。

数据结构

主循环的三个重要结构体,主循环、上下文、事件源,全部为不透明结构体。

typedef struct _GMainLoop GMainLoop;
typedef struct _GMainContext GMainContext;
typedef struct _GSource GSource;

函数列表

GMainLoop * 	g_main_loop_new ()
GMainLoop * 	g_main_loop_ref ()
void 	g_main_loop_unref ()
void 	g_main_loop_run ()
void 	g_main_loop_quit ()
gboolean 	g_main_loop_is_running ()
GMainContext * 	g_main_loop_get_context ()
#define 	g_main_new()
#define 	g_main_destroy()
#define 	g_main_run()
#define 	g_main_quit()
#define 	g_main_is_running()
GMainContext * 	g_main_context_new ()
GMainContext * 	g_main_context_ref ()
void 	g_main_context_unref ()
GMainContext * 	g_main_context_default ()
gboolean 	g_main_context_iteration ()
#define 	g_main_iteration()
gboolean 	g_main_context_pending ()
#define 	g_main_pending
GSource * 	g_main_context_find_source_by_id ()
GSource * 	g_main_context_find_source_by_user_data ()
GSource * 	g_main_context_find_source_by_funcs_user_data ()
void 	g_main_context_wakeup ()
gboolean 	g_main_context_acquire ()
void 	g_main_context_release ()
gboolean 	g_main_context_is_owner ()
gboolean 	g_main_context_wait ()
gboolean 	g_main_context_prepare ()
gint 	g_main_context_query ()
gboolean 	g_main_context_check ()
void 	g_main_context_dispatch ()
void 	g_main_context_set_poll_func ()
GPollFunc 	g_main_context_get_poll_func ()
gint 	(*GPollFunc) ()
void 	g_main_context_add_poll ()
void 	g_main_context_remove_poll ()
gint 	g_main_depth ()
GSource * 	g_main_current_source ()
#define 	g_main_set_poll_func()
void 	g_main_context_invoke ()
void 	g_main_context_invoke_full ()
GMainContext * 	g_main_context_get_thread_default ()
GMainContext * 	g_main_context_ref_thread_default ()
void 	g_main_context_push_thread_default ()
void 	g_main_context_pop_thread_default ()
GSource * 	g_timeout_source_new ()
GSource * 	g_timeout_source_new_seconds ()
guint 	g_timeout_add ()
guint 	g_timeout_add_full ()
guint 	g_timeout_add_seconds ()
guint 	g_timeout_add_seconds_full ()
GSource * 	g_idle_source_new ()
guint 	g_idle_add ()
guint 	g_idle_add_full ()
gboolean 	g_idle_remove_by_data ()
void 	(*GChildWatchFunc) ()
GSource * 	g_child_watch_source_new ()
guint 	g_child_watch_add ()
guint 	g_child_watch_add_full ()
gint 	g_poll ()
void 	(*GSourceDummyMarshal) ()
GSource * 	g_source_new ()
GSource * 	g_source_ref ()
void 	g_source_unref ()
void 	g_source_set_funcs ()
guint 	g_source_attach ()
void 	g_source_destroy ()
gboolean 	g_source_is_destroyed ()
void 	g_source_set_priority ()
gint 	g_source_get_priority ()
void 	g_source_set_can_recurse ()
gboolean 	g_source_get_can_recurse ()
guint 	g_source_get_id ()
const char * 	g_source_get_name ()
void 	g_source_set_name ()
void 	g_source_set_name_by_id ()
GMainContext * 	g_source_get_context ()
void 	g_source_set_callback ()
gboolean 	(*GSourceFunc) ()
void 	g_source_set_callback_indirect ()
void 	g_source_set_ready_time ()
gint64 	g_source_get_ready_time ()
gpointer 	g_source_add_unix_fd ()
void 	g_source_remove_unix_fd ()
void 	g_source_modify_unix_fd ()
GIOCondition 	g_source_query_unix_fd ()
void 	g_source_add_poll ()
void 	g_source_remove_poll ()
void 	g_source_add_child_source ()
void 	g_source_remove_child_source ()
gint64 	g_source_get_time ()
void 	g_source_get_current_time ()
gboolean 	g_source_remove ()
gboolean 	g_source_remove_by_funcs_user_data ()
gboolean 	g_source_remove_by_user_data ()
void 	(*GClearHandleFunc) ()
void 	g_clear_handle_id ()

函数功能分类

主循环自身操作函数

GMainLoop * 	g_main_loop_new ()
GMainLoop * 	g_main_loop_ref ()
void 	g_main_loop_unref ()
void 	g_main_loop_run ()
void 	g_main_loop_quit ()
gboolean 	g_main_loop_is_running ()

上下文操作函数

GMainContext * 	g_main_loop_get_context ()
GMainContext * 	g_main_context_new ()
GMainContext * 	g_main_context_ref ()
void 	g_main_context_unref ()
GMainContext * 	g_main_context_default ()
gboolean 	g_main_context_iteration ()
gboolean 	g_main_context_pending ()
GSource * 	g_main_context_find_source_by_id ()
GSource * 	g_main_context_find_source_by_user_data ()
GSource * 	g_main_context_find_source_by_funcs_user_data ()
void 	g_main_context_wakeup ()
gboolean 	g_main_context_acquire ()
void 	g_main_context_release ()
gboolean 	g_main_context_is_owner ()
gboolean 	g_main_context_wait ()
gboolean 	g_main_context_prepare ()
gint 	g_main_context_query ()
gboolean 	g_main_context_check ()
void 	g_main_context_dispatch ()
void 	g_main_context_set_poll_func ()
GPollFunc 	g_main_context_get_poll_func ()
gint 	(*GPollFunc) ()
void 	g_main_context_add_poll ()
void 	g_main_context_remove_poll ()
gint 	g_main_depth ()
GSource * 	g_main_current_source ()
void 	g_main_context_invoke ()
void 	g_main_context_invoke_full ()
GMainContext * 	g_main_context_get_thread_default ()
GMainContext * 	g_main_context_ref_thread_default ()
void 	g_main_context_push_thread_default ()
void 	g_main_context_pop_thread_default ()

定时器事件源

GSource * 	g_timeout_source_new ()
GSource * 	g_timeout_source_new_seconds ()
guint 	g_timeout_add ()
guint 	g_timeout_add_full ()
guint 	g_timeout_add_seconds ()
guint 	g_timeout_add_seconds_full ()

Idle事件源

GSource * 	g_idle_source_new ()
guint 	g_idle_add ()
guint 	g_idle_add_full ()
gboolean 	g_idle_remove_by_data ()

自定义事件源函数

void 	(*GChildWatchFunc) ()
GSource * 	g_child_watch_source_new ()
guint 	g_child_watch_add ()
guint 	g_child_watch_add_full ()
gint 	g_poll ()
void 	(*GSourceDummyMarshal) ()
GSource * 	g_source_new ()
GSource * 	g_source_ref ()
void 	g_source_unref ()
void 	g_source_set_funcs ()
guint 	g_source_attach ()
void 	g_source_destroy ()
gboolean 	g_source_is_destroyed ()
void 	g_source_set_priority ()
gint 	g_source_get_priority ()
void 	g_source_set_can_recurse ()
gboolean 	g_source_get_can_recurse ()
guint 	g_source_get_id ()
const char * 	g_source_get_name ()
void 	g_source_set_name ()
void 	g_source_set_name_by_id ()
GMainContext * 	g_source_get_context ()
void 	g_source_set_callback ()
gboolean 	(*GSourceFunc) ()
void 	g_source_set_callback_indirect ()
void 	g_source_set_ready_time ()
gint64 	g_source_get_ready_time ()
gpointer 	g_source_add_unix_fd ()
void 	g_source_remove_unix_fd ()
void 	g_source_modify_unix_fd ()
GIOCondition 	g_source_query_unix_fd ()
void 	g_source_add_poll ()
void 	g_source_remove_poll ()
void 	g_source_add_child_source ()
void 	g_source_remove_child_source ()
gint64 	g_source_get_time ()
gboolean 	g_source_remove ()
gboolean 	g_source_remove_by_funcs_user_data ()
gboolean 	g_source_remove_by_user_data ()
void 	(*GClearHandleFunc) ()
void 	g_clear_handle_id ()

已废弃函数

#define 	g_main_new()
#define 	g_main_destroy()
#define 	g_main_run()
#define 	g_main_quit()
#define 	g_main_is_running()
#define 	g_main_iteration()
#define 	g_main_pending
#define 	g_main_set_poll_func()
void 	g_source_get_current_time ()

函数功能说明及综合演示

Idle事件源演示

Idle是GLib内置的事件源,可以处理异步事件。下面程序演示创建一个Idle事件源,在其回调函数内休眠1秒,然后退出主循环。
示例代码如下:
源码见glib_examples\glib_mainloop\glib_mainloop_idle

#include <glib.h>

static gboolean idle_add_func(gpointer data)
{
    GMainLoop *loop = (GMainLoop *)data;
    g_return_if_fail(loop);

    g_print("%s: sleep 1s and quit \n", __FUNCTION__);
    g_usleep(1000*1000);

    g_main_loop_quit(loop);

    return TRUE;
}

gint main (gint argc, gchar **argv)
{
    GMainLoop *loop = NULL;

    loop = g_main_loop_new(NULL, TRUE);

    g_idle_add(idle_add_func, loop);

    g_main_loop_run(loop);

    g_main_loop_unref(loop);

    return 0;
}

运行结果:

[root@centos7_6 build]# ./glib_mainloop_idle
idle_add_func: sleep 1s and quit
[root@centos7_6 build]#
Idle事件源循环执行演示

Idle事件源支持单次执行,也支持多次执行,这取决于其回调函数的返回值。下面的例子,在前五次,都让回调函数返回TRUE,这会使事件会多次被触发,超过5次后,主循环退出。
示例代码如下:
源码见glib_examples\glib_mainloop\glib_mainloop_idle_cycle

#include <glib.h>

static gint s_count = 5;

static gboolean idle_add_func(gpointer data)
{
    GMainLoop *loop = (GMainLoop *)data;
    g_return_if_fail(loop);

    g_print("%s: sleep 500ms and continue \n", __FUNCTION__);
    if(s_count--) {
        g_usleep(500*1000);
        return TRUE;
    }

    g_print("%s: quit mainloop \n", __FUNCTION__);
    g_main_loop_quit(loop);

    return FALSE;
}

gint main (gint argc, gchar **argv)
{
    GMainLoop *loop = NULL;

    loop = g_main_loop_new(NULL, TRUE);

    g_idle_add(idle_add_func, loop);

    g_main_loop_run(loop);

    g_main_loop_unref(loop);

    return 0;
}

运行结果:

[root@centos7_6 build]# ./glib_mainloop_idle_cycle
idle_add_func: sleep 500ms and continue
idle_add_func: sleep 500ms and continue
idle_add_func: sleep 500ms and continue
idle_add_func: sleep 500ms and continue
idle_add_func: sleep 500ms and continue
idle_add_func: sleep 500ms and continue
idle_add_func: quit mainloop
定时器事件源简单演示

定时器是GLib内置的另一个事件源,支持单次执行和循环执行,这取决于事件回调函数的返回值。下面程序演示每隔400毫秒触发一次事件,循环5次后自动退出,使用定时器事件源实现。
示例代码如下:
源码见glib_examples\glib_mainloop\glib_mainloop_timeout_basic

#include <glib.h>

typedef struct loop_info_tag
{
    GMainLoop *loop; /* loop对象 */
    gint loopid; /* loop对象的ID,便于区分多个loop对象 */
    gint count; /* 定时器循环次数 */
    gint interval; /* 定时器每次循环间隔 */
} loop_info_t;

static loop_info_t s_loop;
static GTimer *s_timer = NULL;

static gboolean test_timeout_cbk (gpointer user_data)
{
    loop_info_t *data = user_data;

    if(0 == data->count) {
        g_print("[%f] mainloop(%d) quit! \n", g_timer_elapsed(s_timer, NULL), data->loopid);
        g_main_loop_quit(data->loop);

        return FALSE;
    } else {
        g_print("[%f] mainloop(%d) count=%d \n", g_timer_elapsed(s_timer, NULL), data->loopid, data->count);
        data->count--;
    }

    return TRUE;
}

static gpointer test_timeout_add (gpointer data)
{
    s_loop.count = 5;
    s_loop.interval = 400;
    s_loop.loopid = 101;
    s_loop.loop = g_main_loop_new (NULL, TRUE);

    g_timeout_add (s_loop.interval, test_timeout_cbk, &s_loop);

    g_main_loop_run (s_loop.loop);

    g_main_loop_unref (s_loop.loop);

    return NULL;
}

gint main (gint argc, gchar **argv)
{
    s_timer = g_timer_new();
    g_timer_start(s_timer);

    test_timeout_add(NULL);

    g_timer_stop(s_timer);
    g_timer_destroy(s_timer);

    return 0;
}

运行结果:

[root@centos7_6 build]# ./glib_mainloop_timeout_basic
[0.400595] mainloop(101) count=5
[0.802213] mainloop(101) count=4
[1.203943] mainloop(101) count=3
[1.604542] mainloop(101) count=2
[2.005222] mainloop(101) count=1
[2.405642] mainloop(101) quit!
[root@centos7_6 build]#
两个线程执行两个主循环

GLib有默认的主循环,也可以自己创建主循环,多个主循环可以并行执行。下面程序演示的是在两个线程分别运行两个主循环,第一个主循环内的定时器每400毫秒触发一次且执行5次后自动退出并销毁主循环,第二个主循环内的定时器每500毫秒触发一次且执行5次后也自动退出并销毁主循环。
示例代码如下:
源码见glib_examples\glib_mainloop\glib_mainloop_timeout_two_loops

#include <glib.h>

typedef struct loop_info_tag
{
    GMainLoop *loop; /* loop对象 */
    gint loopid; /* loop对象的ID,便于区分多个loop对象 */
    gint count; /* 定时器循环次数 */
    gint interval; /* 定时器每次循环间隔 */
} loop_info_t;

static loop_info_t s_loop1, s_loop2;
static GTimer *s_timer = NULL;

static gboolean test_timeout_cbk (gpointer user_data)
{
    loop_info_t *data = user_data;

    if(0 == data->count) {
        g_print("[%f] mainloop(%d) quit! \n", g_timer_elapsed(s_timer, NULL), data->loopid);
        g_main_loop_quit(data->loop);

        return FALSE;
    } else {
        g_print("[%f] mainloop(%d) count=%d \n", g_timer_elapsed(s_timer, NULL), data->loopid, data->count);
        data->count--;
    }

    return TRUE;
}

static gpointer test_timeout_add1 (gpointer data)
{
    s_loop1.count = 5;
    s_loop1.interval = 400;
    s_loop1.loopid = 101;
    s_loop1.loop = g_main_loop_new (NULL, TRUE);

    g_timeout_add (s_loop1.interval, test_timeout_cbk, &s_loop1);

    g_main_loop_run (s_loop1.loop);

    g_main_loop_unref (s_loop1.loop);

    return NULL;
}

static gpointer test_timeout_add2 (gpointer data)
{
    s_loop2.count = 5;
    s_loop2.interval = 500;
    s_loop2.loopid = 102;
    s_loop2.loop = g_main_loop_new (NULL, TRUE);

    g_timeout_add (s_loop2.interval, test_timeout_cbk, &s_loop2);

    g_main_loop_run (s_loop2.loop);

    g_main_loop_unref (s_loop2.loop);

    return NULL;
}

gint main (gint argc, gchar **argv)
{
    GThread *th1, *th2;

    s_timer = g_timer_new();
    g_timer_start(s_timer);

    th1 = g_thread_new("th1", test_timeout_add1, NULL);
    th2 = g_thread_new("th2", test_timeout_add2, NULL);

    g_thread_join(th1);
    g_thread_join(th2);

    g_timer_stop(s_timer);
    g_timer_destroy(s_timer);

    return 0;
}

运行结果:

[root@centos7_6 build]# ./glib_mainloop_timeout_two_loops
[0.401876] mainloop(101) count=5
[0.501097] mainloop(102) count=5
[0.803465] mainloop(101) count=4
[1.003345] mainloop(102) count=4
[1.204726] mainloop(101) count=3
[1.504833] mainloop(102) count=3
[1.607050] mainloop(101) count=2
[2.006929] mainloop(102) count=2
[2.008917] mainloop(101) count=1
[2.409765] mainloop(101) quit!
[2.509883] mainloop(102) count=1
[3.011131] mainloop(102) quit!

运行结果表明,不同线程的主循环事件,可以分别执行,互不干扰。

同一线程递归创建主循环

主循环还支持递归方式。
在GTK+中的模态对话框,就是用的主循环递归创建方式。
下面程序演示在主循环中附加了一个定时器事件源,该定时器每100毫秒执行一次,共执行5次,每次执行定时器时,创建新的主循环和定时器事件源,新的主循环和事件源为定时器每200毫秒执行一次共执行5次。
示例代码如下:
源码见glib_examples\glib_mainloop\glib_mainloop_timeout_two_loops_rec

#include <glib.h>

typedef struct loop_info_tag
{
    GMainLoop *loop; /* loop对象 */
    gint loopid; /* loop对象的ID,便于区分多个loop对象 */
    gint count; /* 定时器循环次数 */
    gint interval; /* 定时器每次循环间隔 */
} loop_info_t;

static loop_info_t s_loop;
static loop_info_t s_loop_rec;
static GTimer *s_timer = NULL;
static GTimer *s_timer_rec = NULL;

static gboolean test_rec_timeout_cbk (gpointer user_data)
{
    loop_info_t *data = user_data;
    
    if(0 == data->count) {
        g_print("[%f] mainloop(%d) quit! \n", g_timer_elapsed(s_timer_rec, NULL), data->loopid);
        g_main_loop_quit(data->loop);

        return FALSE;
    } else {
        g_print("[%f] mainloop(%d) count=%d \n", g_timer_elapsed(s_timer_rec, NULL), data->loopid, data->count);
        data->count--;
    }

    return TRUE;
}

static gboolean test_timeout_cbk (gpointer user_data)
{
    loop_info_t *data = user_data;
    
    s_loop_rec.count = 5;
    s_loop_rec.interval = 200;
    s_loop_rec.loopid = 1001;
    s_loop_rec.loop = g_main_loop_new (NULL, TRUE);
    g_timeout_add (s_loop_rec.interval, test_rec_timeout_cbk, &s_loop_rec);

    g_main_loop_run(s_loop_rec.loop);

    g_main_loop_unref(s_loop_rec.loop);

    if(0 == data->count) {
        g_print("[%f] mainloop(%d) quit! \n", g_timer_elapsed(s_timer, NULL), data->loopid);
        g_main_loop_quit(data->loop);

        return FALSE;
    } else {
        g_print("[%f] mainloop(%d) count=%d \n", g_timer_elapsed(s_timer, NULL), data->loopid, data->count);
        data->count--;
    }

    return TRUE;
}

static gpointer test_timeout_add (gpointer data)
{
    s_loop.count = 5;
    s_loop.interval = 100;
    s_loop.loopid = 101;
    s_loop.loop = g_main_loop_new (NULL, TRUE);

    g_timeout_add (s_loop.interval, test_timeout_cbk, &s_loop);

    g_main_loop_run (s_loop.loop);

    g_main_loop_unref (s_loop.loop);

    return NULL;
}

gint main (gint argc, gchar **argv)
{
    s_timer = g_timer_new();
    g_timer_start(s_timer);
    s_timer_rec = g_timer_new();
    g_timer_start(s_timer_rec);

    test_timeout_add(NULL);

    g_timer_stop(s_timer_rec);
    g_timer_destroy(s_timer_rec);

    g_timer_stop(s_timer);
    g_timer_destroy(s_timer);

    return 0;
}

运行结果:

[root@centos7_6 build]# ./glib_mainloop_timeout_two_loops_rec
[0.300846] mainloop(1001) count=5
[0.501389] mainloop(1001) count=4
[0.701749] mainloop(1001) count=3
[0.902501] mainloop(1001) count=2
[1.103414] mainloop(1001) count=1
[1.304495] mainloop(1001) quit!
[1.304533] mainloop(101) count=5
[1.606258] mainloop(1001) count=5
[1.806583] mainloop(1001) count=4
[2.007182] mainloop(1001) count=3
[2.207615] mainloop(1001) count=2
[2.408901] mainloop(1001) count=1
[2.609352] mainloop(1001) quit!
[2.609388] mainloop(101) count=4
[2.910068] mainloop(1001) count=5
[3.110823] mainloop(1001) count=4
[3.311236] mainloop(1001) count=3
[3.512774] mainloop(1001) count=2
[3.713308] mainloop(1001) count=1
[3.913843] mainloop(1001) quit!
[3.913881] mainloop(101) count=3
[4.215282] mainloop(1001) count=5
[4.416084] mainloop(1001) count=4
[4.617323] mainloop(1001) count=3
[4.817651] mainloop(1001) count=2
[5.018708] mainloop(1001) count=1
[5.219372] mainloop(1001) quit!
[5.219406] mainloop(101) count=2
[5.520831] mainloop(1001) count=5
[5.721244] mainloop(1001) count=4
[5.922554] mainloop(1001) count=3
[6.123530] mainloop(1001) count=2
[6.324903] mainloop(1001) count=1
[6.525905] mainloop(1001) quit!
[6.525937] mainloop(101) count=1
[6.826668] mainloop(1001) count=5
[7.027917] mainloop(1001) count=4
[7.228545] mainloop(1001) count=3
[7.428891] mainloop(1001) count=2
[7.629288] mainloop(1001) count=1
[7.829489] mainloop(1001) quit!
[7.829513] mainloop(101) quit!
[root@centos7_6 build]#

运行结果表明,主循环内定时器事件处理函数再次创建的主循环事件执行完,外面的主循环事件才会被继续触发,如果内部的主循环不处理完并退出,外面的主循环不会监听到事件。

同一主循环增加两个事件源

上面讨论的是多个主循环执行的情况,本小节讨论同一主循环添加多个事件源的情形。
在同一主循环上,添加两个定时器事件源,一个时间间隔为500毫秒,一个时间间隔为300毫秒,执行次数都是5。
示例代码如下:
源码见glib_examples\glib_mainloop\glib_mainloop_timeout_two_sources

#include <glib.h>

static GMainLoop *s_loop;
static GTimer *s_timer1, *s_timer2;

static gint s_interval1= 500, s_interval2 = 300;
static gint s_count1 = 5, s_count2 = 5;

static gboolean timeout1_cbk (gpointer user_data)
{
    if(0 == s_count1) {
        g_print("[%f] mainloop(timeout1_cbk) cbk quit! \n", g_timer_elapsed(s_timer1, NULL));
        if(0 == s_count2) {
            g_main_loop_quit(s_loop);
        }

        return FALSE;
    } else {
        g_print("[%f] mainloop(timeout1_cbk) count=%d \n", g_timer_elapsed(s_timer1, NULL), s_count1);
        s_count1--;
    }

    return TRUE;
}

static gboolean timeout2_cbk (gpointer user_data)
{
    if(0 == s_count2) {
        g_print("[%f] mainloop(timeout2_cbk) cbk quit! \n", g_timer_elapsed(s_timer2, NULL));
        if(0 == s_count1) {
            g_main_loop_quit(s_loop);
        }

        return FALSE;
    } else {
        g_print("[%f] mainloop(timeout2_cbk) count=%d \n", g_timer_elapsed(s_timer2, NULL), s_count2);
        s_count2--;
    }

    return TRUE;
}

gint main (gint argc, gchar **argv)
{
    GMainContext *context;
    GSource *tsource1, *tsource2;
    GSource *isource;

    context = g_main_context_new();

    tsource1 = g_timeout_source_new(s_interval1);
    g_source_set_callback(tsource1, timeout1_cbk, NULL, NULL);
    g_source_attach(tsource1, context);

    tsource2 = g_timeout_source_new(s_interval2);
    g_source_set_callback(tsource2, timeout2_cbk, NULL, NULL);
    g_source_attach(tsource2, context);


    s_timer1 = g_timer_new();
    g_timer_start(s_timer1);
    
    s_timer2 = g_timer_new();
    g_timer_start(s_timer2);

    s_loop = g_main_loop_new(context, FALSE);
    g_main_loop_run(s_loop);

    g_main_loop_unref(s_loop);
    g_main_context_unref(context);

    g_source_unref(tsource1);
    g_source_unref(tsource2);

    g_timer_stop(s_timer1);
    g_timer_destroy(s_timer1);
    g_timer_stop(s_timer2);
    g_timer_destroy(s_timer2);

    return 0;
}

运行结果:

[root@centos7_6 build]# ./glib_mainloop_timeout_two_sources
[0.301307] mainloop(timeout2_cbk) count=5
[0.500783] mainloop(timeout1_cbk) count=5
[0.602648] mainloop(timeout2_cbk) count=4
[0.903686] mainloop(timeout2_cbk) count=3
[1.002022] mainloop(timeout1_cbk) count=4
[1.205204] mainloop(timeout2_cbk) count=2
[1.503201] mainloop(timeout1_cbk) count=3
[1.506064] mainloop(timeout2_cbk) count=1
[1.807311] mainloop(timeout2_cbk) cbk quit!
[2.003985] mainloop(timeout1_cbk) count=2
[2.505379] mainloop(timeout1_cbk) count=1
[3.006247] mainloop(timeout1_cbk) cbk quit!
[root@centos7_6 build]#

同一主循环上的事件源均会被调用到并被执行。

同一主循环增加两个优先级不同的事件源

同一主循环的事件源支持优先级设置,优先级高的事件源会先被通知到。
示例代码如下:
源码见glib_examples\glib_mainloop\glib_mainloop_timeout_two_sources_priority

#include <glib.h>

static GMainLoop *s_loop;
static GTimer *s_timer1, *s_timer2;

static gint s_interval1= 1, s_interval2 = 1;
static gint s_count1 = 5, s_count2 = 5;

static gboolean timeout1_cbk (gpointer user_data)
{
    if(0 == s_count1) {
        g_print("[%f] mainloop(timeout1_cbk) cbk quit! \n", g_timer_elapsed(s_timer1, NULL));
        if(0 == s_count2) {
            g_main_loop_quit(s_loop);
        }

        return FALSE;
    } else {
        g_print("[%f] mainloop(timeout1_cbk) count=%d \n", g_timer_elapsed(s_timer1, NULL), s_count1);
        s_count1--;
    }

    return TRUE;
}

static gboolean timeout2_cbk (gpointer user_data)
{
    if(0 == s_count2) {
        g_print("[%f] mainloop(timeout2_cbk) cbk quit! \n", g_timer_elapsed(s_timer2, NULL));
        if(0 == s_count1) {
            g_main_loop_quit(s_loop);
        }

        return FALSE;
    } else {
        g_print("[%f] mainloop(timeout2_cbk) count=%d \n", g_timer_elapsed(s_timer2, NULL), s_count2);
        s_count2--;
    }

    return TRUE;
}

gint main (gint argc, gchar **argv)
{
    GMainContext *context;
    GSource *tsource1, *tsource2;
    GSource *isource;

    context = g_main_context_new();

    tsource1 = g_timeout_source_new(s_interval1);
    g_source_set_priority (tsource1, G_PRIORITY_LOW);
    g_source_set_callback(tsource1, timeout1_cbk, NULL, NULL);
    g_source_attach(tsource1, context);

    tsource2 = g_timeout_source_new(s_interval2);
    g_source_set_priority (tsource2, G_PRIORITY_HIGH);
    g_source_set_callback(tsource2, timeout2_cbk, NULL, NULL);
    g_source_attach(tsource2, context);


    s_timer1 = g_timer_new();
    g_timer_start(s_timer1);
    
    s_timer2 = g_timer_new();
    g_timer_start(s_timer2);

    s_loop = g_main_loop_new(context, FALSE);
    g_main_loop_run(s_loop);

    g_main_loop_unref(s_loop);
    g_main_context_unref(context);

    g_source_unref(tsource1);
    g_source_unref(tsource2);

    g_timer_stop(s_timer1);
    g_timer_destroy(s_timer1);
    g_timer_stop(s_timer2);
    g_timer_destroy(s_timer2);

    return 0;
}

运行结果:

[root@centos7_6 build]# ./glib_mainloop_timeout_two_sources_priority
[0.001389] mainloop(timeout2_cbk) count=5
[0.001515] mainloop(timeout1_cbk) count=5
[0.003507] mainloop(timeout2_cbk) count=4
[0.003522] mainloop(timeout1_cbk) count=4
[0.004570] mainloop(timeout2_cbk) count=3
[0.004583] mainloop(timeout1_cbk) count=3
[0.006450] mainloop(timeout2_cbk) count=2
[0.006473] mainloop(timeout1_cbk) count=2
[0.008389] mainloop(timeout2_cbk) count=1
[0.008408] mainloop(timeout1_cbk) count=1
[0.009498] mainloop(timeout2_cbk) cbk quit!
[root@centos7_6 build]# ./glib_mainloop_timeout_two_sources_priority
[0.001229] mainloop(timeout2_cbk) count=5
[0.001362] mainloop(timeout1_cbk) count=5
[0.003331] mainloop(timeout2_cbk) count=4
[0.003345] mainloop(timeout1_cbk) count=4
[0.005327] mainloop(timeout2_cbk) count=3
[0.005340] mainloop(timeout1_cbk) count=3
[0.007233] mainloop(timeout2_cbk) count=2
[0.007247] mainloop(timeout1_cbk) count=2
[0.008327] mainloop(timeout2_cbk) count=1
[0.008340] mainloop(timeout1_cbk) count=1
[0.010320] mainloop(timeout2_cbk) cbk quit!
[root@centos7_6 build]#

虽然事件源2比事件源1被添加的晚,但由于事件源2的优先级高,每次执行时,均会比事件源1执行得早。多次运行,得到的结果一样,始终是事件源2的回调函数先执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值