ST源码分析-st_usleep

SRS 的社群来了,想加入微信社群的朋友请购买《SRS原理》电子书,里有更高级的内容与答疑服务。


由于 ST 库是单线程程序,如果使用了 unistd.h 里面的 sleep() 或者 usleep() 函数,就会阻塞所有协程函数的执行。但是有时候,某个协程确实要 sleep 休眠一些时间,那怎么办?

ST 库提供了 st_usleep() 函数,使用这个函数,就可以让某个协程休眠一段时间,但是又不会阻塞其他的协程函数的执行。下面就用一小段代码演示一下 st_usleep() 的用法,代码如下,为了简洁,省略了错误处理。

#include <stdio.h>
#include "st.h"
#include "../common.h"
​
void *print_a(void *arg) {
    st_usleep(2 * 1000000LL);
    st_utime_t time_now = st_utime();
    printf("I am a , %lld\r\n", time_now);
    return NULL;
}
​
void *print_b(void *arg) {
    st_utime_t time_now = st_utime();
    printf("I am b , %lld\r\n", time_now);
    return NULL;
}
​
int main(int argc, char *argv[]) {
    st_init();
​
    st_thread_create(print_a, NULL, 0, 0);
    st_thread_create(print_b, NULL, 0, 0);
​
    st_thread_exit(NULL);
​
    /* NOTREACHED */
    return 1;
}

执行之后的结果如下图:

从上图看到,b 协程 sleep 并不会阻塞 a 协程的运行。


下面就来分析一次 st_usleep() 的实现原理。

重点如下图:

上面的代码,把 a 协程状态改成 _ST_ST_SLEEPING ,然后把 a 协程加进去 SLEEPQ 队列,然后就 开始用 _ST_SWITCH_CONTEXT() 切换协程,此时 a 协程就会被挂起,因为 系统线程 已经切换到别的地方运行了, 所以 a 协程看起来是阻塞了。

从之前的文章中,我们知道 _ST_SWITCH_CONTEXT() 会不断地调 _st_vp_schedule() 来调度处理其他协程,处理完其他协程之后,就会进入 _st_idle_thread_start()

也就是说,b 协程跑完之后,就会进入 _st_idle_thread_start(),请看下图:

从上图可以看到,_st_vp_check_clock() 就是处理 进入 _ST_ST_SLEEPING 状态的协程。代码如下图:

_st_vp_check_clock() 函数有3个重点:

1,变量 elapsed 没有用到。

2,使用 if (thread->due > now) 来判断 时间是否到了,这里 thread->due 的实现非常有趣,due 是在 _st_add_sleep_q() 加入 SLEEPQ 队列的时候赋值的,如下:

下面就来看看 _ST_LAST_CLOCK 是什么时候赋值的,如下图:

从上图可以看到,_ST_LAST_CLOCK 是在上一次调度的时候赋值的。因此,如果 从上一次上下文切换到现在已经过去了8毫秒,而 st_usleep() 为10毫秒,那么 在 调用 st_usleep() 之后,可能 再过2毫秒 就会立即返回。

3,_ST_DEL_SLEEPQ(thread); -> thread->state = _ST_ST_RUNNABLE -> _ST_ADD_RUNQ(thread)

主要就上面这几行代码,时间到了,就把 协程从 SLEEPQ 删除,把协程状态改成 _ST_ST_RUNNABLE,再加进去 RUNQ 队列, 然后下次 _st_vp_schedule() 调度, _ST_ST_RUNNABLE 状态的协程就能继续跑。


不过上面的这种 sleep 实现,会有一个问题,因为是处理完其他协程才会进入 _st_idle_thread_start(),如果其他的协程是计算密集型的,消耗太多的时间,就没法及时唤醒 处于 sleep 中的协程。

操作系统 unistd.h 里面的 sleep() 或者 usleep() 函数 应该类似的问题,如果其他线程太耗时,CPU爆满,会没法及时切换来唤醒 sleep中的线程。


由于笔者的水平有限, 加之编写的同时还要参与开发工作,文中难免会出现一些错误或者不准确的地方,恳请读者批评指正。如果读者有任何宝贵意见,可以加我微信 Loken1。QQ:2338195090。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Loken2020

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值