简介
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的回调函数先执行。