Timeouts, IO及Idle函数(GTK)

本文介绍了GTK中的三种事件管理方式:Timeouts用于定时触发任务;监督IO用于监控文件描述符的状态变化;Idle函数则确保在空闲时执行特定操作。文章详细讲解了各函数的用法及其如何控制回调函数的执行。

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

Timeouts, IO及Idle函数

1 Timeouts

您可能会想要在gtk_man idle时, 做一些事情. 你有好几个选择. 使用以下这些函数可以产生一个timeout函数, 它每间隔一阵子就会去呼叫您的函数.

gint gtk_timeout_add (guint32 interval,
GtkFunction function,
gpointer data);

第一个参数是每间隔interval milliseconds会去呼叫您的函数. 第二个是该函数. 第三个是要传给该函数的资料. 返回值则为该行程的"标签".

void gtk_timeout_remove (gint tag);

您可以在您的timeout函数返回zero或FALSE来停止timeout函数. 这就是说您必须返回非零值, 如TRUE.

你的callback函数必须像这样:

gint timeout_callback (gpointer data);

2 监督IO

GTK另一个漂亮的功能是有办法去检查一个file descriptor的资料. (as returned by open(2) or socket(2)). 这个在网路软体上很有用:

gint gdk_input_add (gint source,
GdkInputCondition condition,
GdkInputFunction function,
gpointer data);

第一个参数是您想看的file descriptor, 第二个是你要GDK去看那一项, 可以是以下几项:

GDK_INPUT_READ - 当file descriptor有资料的时候会去呼叫您的函数.

GDK_INPUT_WRITE - 当您的file descriptor可以被写入资料的时候.

第三个当然是callback函数. 第四个是要传给callback的资料.

返回值是可用来停止监督的一个"标签".

void gdk_input_remove (gint tag);

当您的callback函数返回zero或FALSE时, GTK会停止呼叫您的callback函数.

3 Idle函数

当什麽事情都不发生时, 您要呼叫一个函数时要怎麽办?

gint gtk_idle_add (GtkFunction function,
gpointer data);

当什麽事都不发生时, GTK会去呼叫这个函数.

void gtk_idle_remove (gint tag);

这个不用解释了吧. 您若在idle函数返回zero或FALSE会停止idle函数的运行.

 
<think>嗯,用户这次想了解LwIP中sys_timeouts_sleeptime函数的功能和原理。结合历史对话,用户之前已经研究过tcpip_thread的阻塞机制和超时处理,现在需要深入这个关键函数的具体实现。用户引用的资料很有价值:引用[1]提到周期性超时处理,引用[2]解释了时间比较的特殊逻辑,引用[3]展示了sys_timeouts_init的初始化位置。这些都能帮助我们还原sys_timeouts_sleeptime的全貌。首先必须明确这个函数的核心作用:计算距离下一个超时事件的时间差,供任务调度使用。它实际上是LwIP定时器系统的调度中枢。具体实现上有几个技术要点值得展开:一是时间链表遍历机制,需要从全局链表头timeouts_head开始逐个比较超时时间;二是特殊的时间比较算法,采用TIME_LESS_THAN宏处理32位整数回绕问题(如0xFFFFFFFF和0的比较);三是临界区保护,整个计算过程需要加锁防止链表被修改。用户可能还会关心实际应用场景。比如在tcpip_thread主循环里:先用这个函数获取最大可阻塞时长,然后带着这个超时参数去等待邮箱,这样既能及时响应网络事件,又能保证定时任务准时执行。考虑到用户的研究深度,后续可能会对时间精度或性能优化感兴趣,所以在相关问题上可以引导这些方向。比如测量定时器响应抖动的方法,或者多定时器场景下的优化思路。</think> ### `sys_timeouts_sleeptime()`函数详解 `sys_timeouts_sleeptime()`是LwIP定时器系统的核心函数,其**核心功能**是: **计算距离最近超时事件的剩余时间**,为线程阻塞提供精确的超时依据[^1][^3]。该函数原理如下: --- #### **一、函数原型与调用位置** ```c sys_timeouts_sleeptime(void); ``` **调用位置**: 在`tcpip_thread()`主循环中被调用,嵌入邮箱阻塞操作: ```c sys_arch_mbox_fetch(&tcpip_mbox, (void**)&msg, timeout = sys_timeouts_sleeptime()); ``` --- #### **二、工作原理分步解析** ##### **步骤1:遍历超时链表** 超时事件按触发时间升序存储在全局链表`next_timeout`中: ```c struct sys_timeo *next_timeout; // 全局超时链表头指针 ``` ![超时链表结构](https://i.imgur.com/9RrGgHX.png) *注:链表节点按`time`字段有序排列,`time`表示从系统启动到触发时刻的毫秒数[^1]。* ##### **步骤2:计算睡眠时间** $$ \text{sleeptime} = \min(\text{next_timeout} \to \text{time} - \text{now}, \ \text{MAX_DELAY}) $$ 其中: - `now` = 当前系统时间戳(毫秒) - `MAX_DELAY` = 最大允许阻塞时间(典型值`0x7FFFFFFF` ms) ###### **关键处理:32位时间回绕** 采用特殊比较宏`TIME_LESS_THAN`: ```c #define TIME_LESS_THAN(a, b) ((s32_t)((a) - (b)) < 0) ``` **原理**: 当时间差超过$2^{31}$毫秒(约24.8天)时,32位时间戳会发生回绕。 例如: - 当前时间`now=0xFFFFFFF0` - 超时时间`time=0x00000010` 表面差值 = $0x00000010 - 0xFFFFFFF0 = 0xFFFFFF20$(负值) 实际应为 $(\mathrm{0x00000010} + \mathrm{0xFFFFFFFF}) - \mathrm{0xFFFFFFF0} + 1 = 32\mathrm{ms}$ `TIME_LESS_THAN`通过有符号比较解决回绕问题[^2]。 ##### **步骤3:临界区保护** 整个计算过程在系统锁保护下进行: ```c sys_timeouts_sleeptime(void) { SYS_ARCH_DECL_PROTECT(old_level); // 声明保护变量 SYS_ARCH_PROTECT(old_level); // 进入临界区 // ... 计算逻辑 ... SYS_ARCH_UNPROTECT(old_level); // 退出临界区 return sleeptime; } ``` 避免在计算过程中超时链表被中断修改[^1]。 --- #### **三、典型工作流程** ```mermaid sequenceDiagram tcpip_thread->>sys_timeouts_sleeptime: 计算阻塞时间 sys_timeouts_sleeptime-->>tcpip_thread: 返回Δt (如200ms) tcpip_thread->>sys_arch_mbox_fetch: 带Δt阻塞邮箱 alt 超时前收到数据 邮箱-->>tcpip_thread: 唤醒并处理数据包 else Δt超时 tcpip_thread->>sys_check_timeouts: 执行超时回调 sys_check_timeouts->>周期性定时器: 重新注册[^1] end ``` --- #### **四、设计目标与优势** 1. **精准调度** 确保在最近超时事件到来前唤醒线程,避免定时延误 2. **零空闲消耗** 无超时事件时返回`SYS_TIMEOUTS_SLEEPTIME_INFINITE`(通常`0x7FFFFFFF`),线程可长期阻塞 3. **低延迟响应** 邮箱事件和超时事件共用同一唤醒机制,降低响应延迟[^3] ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值