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()了
分享到:
相关推荐
封装好的自动创建多层文件夹函数: // 如此调用,则会在C:\123目录下创建名为111的文件夹,111文件夹下又自动创建222,依次类推 CreateMultilFolder("C:\123", "111/222/333")
用数组创建函数创建一个二维数组显示件,成员为: 4 5 6 1 2 3 3 4 5 6 1 2 2 3 4 5 6 1 1 2 3 4 5 6 编程将上述创建的数组转置为: 1 2 3 4 2 3 4 5 3 4 5 6 4 5 6 1 5 6 1 2 6 1 2 3
总的来说,C++的绘图功能依赖于选择的库,而创建填充区涉及选择合适的绘图函数、设置填充规则和颜色,以及正确管理绘图上下文。通过实践和学习库的文档,你可以掌握这些技能,为你的项目添加丰富的图形元素。
存储函数创建完后,就如同系统提供的内置函数(如VERSION()),所以调用存储函数的方法也差不多,都是使用SELECT关键字。 【例】 创建一个存储函数,返回Book表中某本书的作者姓名。 存储函数举例 DELIMITER $$ ...
MySQL数据库:存储函数的创建.pptx
构造函数的主要作用是在创建对象时初始化该对象。构造函数可以重载,这意味着一个类中可以有多个构造函数,只要它们的参数列表不同即可。 例如,考虑`Location`类,它定义了三个构造函数:无参构造函数、一个接受...
本文将详细介绍如何通过创建一个名为`my_password_verify`的自定义函数来实现对Oracle用户密码复杂度的控制。 #### 一、背景介绍 在Oracle数据库中,默认情况下并没有内置的功能可以直接限制用户的密码复杂度。...
在创建自定义聚合函数时,还需要定义一个对象类型(Object Type),这个对象类型将包含四个 ODCIAggregate 接口函数的实现。然后,使用 CREATE FUNCTION 语句来创建自定义的聚合函数。 例如,以下是一个简单的...
在本篇上机练习中,我们将探讨Python编程中的核心概念——创建和调用函数,这是程序设计中的基本技能。函数是可重复使用的代码块,能够提高代码的复用性和模块化,使得程序更加清晰和易于维护。在此,我们将会通过两...
然而,有时Hive的内置函数并不能满足所有的业务需求,这时我们就需要创建自定义函数(UDF,User Defined Function)。这篇博文主要探讨了如何在Hive中创建自定义函数以及如何加载它们,这对于深化Hive的使用和解决...
由于成员函数需要对象实例才能被调用,因此在创建线程时需要提供对象的引用或指针。 ```cpp MyClass obj; std::thread my_thread(&MyClass::threadFunction, &obj, 42); // 42 是传递给成员函数的参数 ``` 三、...
构造函数是一种特殊的类成员函数,是当创建一个类的对象时,它被调用来对类的数据成员进行初始化和分配内存。(构造函数的命名必须和类名完全相同) 首先说一下一个C++的空类,编译器会加入哪些默认的成员函数 默认...
这种方式创建的函数会在声明时立即执行,且无法再次调用。例如: ```javascript (function() { // 函数体 })(); // 立即执行 ``` 3. **使用`Function`构造函数** `Function`构造函数允许动态创建函数,但...
MATLAB提供了丰富的函数库来创建和操作各种类型的隶属函数,如三角函数、梯形函数、高斯函数等。例如,可以使用`trapezoid`函数构建梯形函数,`gaussmf`函数构建高斯型函数。这些函数允许用户自定义参数,以适应特定...
1. **用途**:函数指针用于动态调用函数,它允许我们在运行时决定调用哪个函数,增强了程序的灵活性。而指针函数则主要用于返回一个指向数据的指针,它关注的是数据的创建和访问。 2. **类型**:函数指针是一种特殊...
构造函数是在创建类的对象时自动调用的一种特殊成员函数,主要用于初始化对象的数据成员。`cPerson`类中有三种构造函数: 1. **默认构造函数**:`cPerson::cPerson()`,当没有提供任何参数来创建`cPerson`对象时,...
空函数,也称为“占位符”或“哑函数”,在很多场景下都大有用处,例如充当临时的回调函数、默认行为或者保留未来扩展的接口。下面我们将详细讨论如何创建空函数,以及它们在实际开发中的应用。 首先,让我们看看...
创建线程时,我们需要提供一个线程函数,这个函数将在新线程中运行。在这个例子中,线程函数可能会用于创建和显示窗口。线程函数通常会遵循这样的步骤: 1. 初始化窗口类(WNDCLASS):设置窗口类的风格、背景刷、...
在创建DLL回调函数时,开发者需要遵循以下步骤: 1. **定义回调函数**: 在DLL和应用程序之间定义一个公共函数原型,通常是在头文件中。这个函数必须是C语言兼容的,因为C++的成员函数不能直接作为回调函数使用。 2...
虚函数的作用在于通过父类的指针或者引用来调用它的时候能够变成调用子类的那个成员函数,而构造函数是在创建对象时自动调用的,不可能通过父类的指针或者引用去调用,因此也就规定构造函数不能是虚函数。...