SRS的协程ID-SrsContextId—SRS源码分析
作者:罗上文,微信:Loken1,公众号:FFmpeg弦外之音
SRS 给每个协程都赋予了一个 ID(SrsContextId
),由于 SRS 每处理一个 RTMP 客户端连接,都使用一个协程,所以这个 ID 也可以理解为 连接ID,连接ID 就是 SrsRtmpConn
的 ID,这样可以追踪到具体是哪个客户端出现的问题。
协程ID在两个地方都有存储的。
SrsFastCoroutine
类的cid_
字段。- 协程的 private data 里面,通过
st_thread_setspecific2()
设置的,请阅读《st_thread_setspecific协程私有数据》
但是生成这个协程ID的逻辑是比较绕的,一共有 3 处地方会去设置 协程 ID,如下:
1,SrsFastCoroutine 的构造函数
SrsFastCoroutine
的构造函数可以接收协程 ID,不过有时候传进来的 ID 是空的。所以并没有设置成功,例如 SrsFastTimer
协程。
没有成功设置 协程 ID 会怎样呢?会在 SrsFastCoroutine::cycle()
里面再设置一下,现在就来到了第二处设置 协程 ID 的地方。
2,SrsFastCoroutine::cycle()
在 SrsFastCoroutine::cycle()
里会检测一下 协程ID,如果没设置会再设置一下,如下:
疑问:上面他为什么要判断一下 _srs_context
是否有值,应该肯定是有值的啊?
这里我有必要介绍一下 _srs_context
这个变量,他是一个全局变量来的。_srs_context
变量的类型虽然是 ISrsContext
,但是他的实际却是 SrsThreadContext
,如下:
ISrsContext* _srs_context = NULL;
_srs_context = new SrsThreadContext();
SrsThreadContext
类有 3 个方法,如下:
generate_id()
,生成一个协程ID 返回。get_id()
,获取当前协程的ID,如果还没有当前协程,会先用_srs_context_default
来凑数,这个_srs_context_default
感觉他一直是一个空的东西,没有被赋值。可能 default(默认),默认的协程ID 就是空吧。set_id()
,把协程ID 设置进当前 协程的private data
里面的。
不要被 _srs_context
这个变量名误导,以为他是某个协程的上下文,他不是,他只是一个管理器。负责生成或者获取协程的ID。
第三处设置协程 ID 的地方就是 SrsFastCoroutine::set_cid()
函数
3,SrsFastCoroutine::set_cid()
SrsFastCoroutine::set_cid()
函数直接就是两个地方的 协程ID 都一下子就设置了,如下:
void SrsFastCoroutine::set_cid(const SrsContextId& cid)
{
cid_ = cid;
srs_context_set_cid_of(trd, cid);
}
我觉得前面两处设置 协程 ID 的地方是最重要的,先来讲一下什么场景下传递给 SrsFastCoroutine
构造函数的 协程ID 是空呢?
在 SrsThreadPool::setup_thread_locals()
之前创建的协程,他们的 协程ID 都是空。 setup_thread_locals()
里面会调 srs_st_init()
进行初始化协程库。
在此之前,始祖协程都没初始化出来的,所以 srs_thread_self()
获取不到当前协程,就会返回 _srs_context_default
,而 _srs_context_default
也没赋值,也是一个空的东西。流程如下:
他这个逻辑我觉得是有点绕的,反正就是这么一回事。有补救策略,如果在构造函数没成功设置 协程ID,就会在 SrsFastCoroutine::cycle()
里面再设置一下。
不过说实话,我也不太理解 _srs_context_default
这个东西是干什么用的,好像都没对它进行赋值,一直是空。