GSource 创建时各函数的用处

本文详细解析了GLib Mainloop的工作原理,通过四个关键步骤:准备(prepare)、检查(check)、分发(dispatch)和销毁(finalize),展示了如何管理事件和定时任务。并通过一个具体的例子演示了不同源(Source)如何在Mainloop中交互。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.prepare:

进入睡眠之前,在g_main_context_prepare里,mainloop调用所有Source的prepare函数,计算最小的timeout时间,该时间决定下一次睡眠的时间。

2.check:

poll被唤醒后,在g_main_context_check里,mainloop调用所有Source的check函数,检查是否有Source已经准备好了。如果poll是由于错误或者超时等原因唤醒的,就不必进行dispatch了。

3.dispatch:

当有Source准备好了,在g_main_context_dispatch里,mainloop调用所有Source的dispatch函数,去分发消息。

4.finalize:

在Source被移出时,mainloop调用该函数去销毁Source。



实例验证:

1.创建两个GSource,一个2秒醒一次,一个3秒醒一次。

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>

#include <glib.h>

typedef struct _DemoSource DemoSource;
struct _DemoSource
{
GSource source;
int interval;
GTimeVal last;
};

DemoSource *s1, *s2;
const char* cur_source_name = NULL;

static glong my_time_val_difference (const GTimeVal *compare, const GTimeVal *now)
{
return (compare->tv_sec - now->tv_sec) * 1000 + (compare->tv_usec - now->tv_usec) / 1000;
}

static const char* get_source_str( GSource* source_ )
{
if( (unsigned int)source_ == (unsigned int)s1 ) return "s1";
else if( (unsigned int)source_ == (unsigned int)s2 ) return "s2";

return "unkown";
}

static gboolean prepare_func( GSource *source_, gint *timeout )
{
DemoSource* source = (DemoSource*)source_;
GTimeVal now, target;
glong diff;

cur_source_name = get_source_str( source_ );

g_source_get_current_time( source_, &now );

target = source->last;
g_time_val_add( &target, source->interval );

diff = my_time_val_difference( &now, &target );

printf("-----%s Enter -----\n", __FUNCTION__);

if( diff >= 0 )
{
*timeout = 0;
printf( "Source %s need to dispatch right now. D:%d\n", cur_source_name, diff );
return TRUE;
}
else
{
*timeout = -diff;
printf( "Source %s need to sleep %d ms.\n", cur_source_name, *timeout );
return FALSE;
}
printf("-----%s Exit-----\n", __FUNCTION__);
}

static gboolean check_func( GSource* source_ )
{
DemoSource* source = (DemoSource*)source_;
GTimeVal now, target;
glong diff;

cur_source_name = get_source_str( source_ );

g_source_get_current_time( source_, &now );

target = source->last;
g_time_val_add( &target, source->interval );

diff = my_time_val_difference( &now, &target );

printf("-----%s Enter -----\n", __FUNCTION__);
if( diff >= 0 )
{
printf("Yes. Source %s need to dispatch.\n", cur_source_name );
return TRUE;
}
else
{
printf("No. Source %s want to sleep.\n", cur_source_name );
return FALSE;
}
printf("-----%s Exit-----\n", __FUNCTION__);
}

static gboolean dispatch_func(GSource *source_, GSourceFunc callback, gpointer user_data)
{
cur_source_name = get_source_str( source_ );
printf("-----%s Enter -----\n", __FUNCTION__);
DemoSource* source = (DemoSource*)source_;
g_get_current_time( &source->last );
printf("Source %s dispatched.\n", cur_source_name);
printf("-----%s Exit-----\n", __FUNCTION__);
}

static void finalize_func( GSource* source_ )
{
cur_source_name = get_source_str( source_ );
printf("-----%s Enter -----\n", __FUNCTION__);
printf("Source %s finalized.\n", cur_source_name );
printf("-----%s Exit-----\n", __FUNCTION__);
}

SourceFuncs source_funcs =
{
prepare_func,
check_func,
dispatch_func,
finalize_func,
};

int main( int argc, char** argv )
{
GMainLoop* loop;

loop = g_main_loop_new( NULL, TRUE );

s1 = (DemoSource*)g_source_new( &source_funcs, sizeof(DemoSource) );
s2 = (DemoSource*)g_source_new( &source_funcs, sizeof(DemoSource) );
s1->interval = 2000*1000; //ms
s2->interval = 3000*1000;

g_get_current_time( &s1->last );
g_get_current_time( &s2->last );

g_source_attach( (GSource*)s1, NULL );
g_source_attach( (GSource*)s2, NULL );

printf( "s1 addr:0x%x\n", (unsigned int)s1 );
printf( "s2 addr:0x%x\n", (unsigned int)s2 );

g_main_loop_run( loop );

return 0;
}


2.编译后的输出结果:

s1 addr:0x804ae98
s2 addr:0x804b500
-----prepare_func Enter -----
Source s1 need to sleep 2000 ms.
-----prepare_func Enter -----
Source s2 need to sleep 3000 ms.


-----check_func Enter -----
Yes. Source s1 need to dispatch.
-----check_func Enter -----
No. Source s2 want to sleep.
-----dispatch_func Enter -----
Source s1 dispatched.
-----dispatch_func Exit-----
-----prepare_func Enter -----
Source s1 need to sleep 2000 ms.
-----prepare_func Enter -----
Source s2 need to sleep 1000 ms.


-----check_func Enter -----
No. Source s1 want to sleep.
-----check_func Enter -----
Yes. Source s2 need to dispatch.
-----dispatch_func Enter -----
Source s2 dispatched.
-----dispatch_func Exit-----
-----prepare_func Enter -----
Source s1 need to sleep 1000 ms.
-----prepare_func Enter -----
Source s2 need to sleep 3000 ms.



-----check_func Enter -----
Yes. Source s1 need to dispatch.
-----check_func Enter -----
No. Source s2 want to sleep.
-----dispatch_func Enter -----
Source s1 dispatched.
-----dispatch_func Exit-----
-----prepare_func Enter -----
Source s1 need to sleep 2000 ms.
-----prepare_func Enter -----
Source s2 need to sleep 2000 ms.

3.结果分析:

(1)首先2个source的prepare函数被调用。一个要呼2秒,一个要呼3秒

(2)2秒后2个source的check函数被调用。s1确实是要dispatch,s2回答不关我事,不要叫我

(3)s1被dispatch。

(4)两个source的prepare函数再次调用。一个要呼2秒,一个再继续呼1秒

(5)再次check

(6)再次dispatch。

循环往复

4.个人理解:

mainloop相当于管家,先问下(prepare())诸位大概什么时候用餐(dispatch())。统计后就设一个闹钟,到时提醒。但是由于没记下各自的时间,所以让大家再确认一下是不是自己(check()),如果check返回true,那么就被dispatch()了。

或者由于外界事件,比如冰淇淋在大家呼呼的过程中送来了,管家就叫大家check()一下。虽然没到时间,但是如果check()返回true,那么也直接dispatch()了
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值