SRS源码中的Thread是一层套一层,最终的Thread类是在 srs_app_thread.cpp 的 SrsThread

这里我们暂且先放下协程的概念,把它当线程来看,其逻辑如下:

1. 在start() 方法中创建线程:

 int SrsThread::start()
{
int ret = ERROR_SUCCESS; if(tid) {
srs_info("thread %s already running.", _name);
return ret;
} if((tid = st_thread_create(thread_fun, this, (_joinable? :), )) == NULL){
ret = ERROR_ST_CREATE_CYCLE_THREAD;
srs_error("st_thread_create failed. ret=%d", ret);
return ret;
} disposed = false;
// we set to loop to true for thread to run.
loop = true; // wait for cid to ready, for parent thread to get the cid.
while (_cid < ) {
st_usleep( * );
} // now, cycle thread can run.
can_run = true; return ret;
}

2. 执行的函数是 thread_fun,参数是其本身即: this,再实际调用 this->thread_cycle()

void* SrsThread::thread_fun(void* arg)
{
SrsThread* obj = (SrsThread*)arg;
srs_assert(obj); obj->thread_cycle(); // for valgrind to detect.
SrsThreadContext* ctx = dynamic_cast<SrsThreadContext*>(_srs_context);
if (ctx) {
ctx->clear_cid();
} st_thread_exit(NULL); return NULL;
}

3. thread_cycle() 实现如下:

void SrsThread::thread_cycle()
{
int ret = ERROR_SUCCESS; _srs_context->generate_id();
srs_info("thread %s cycle start", _name); _cid = _srs_context->get_id(); srs_assert(handler);
handler->on_thread_start(); // thread is running now.
really_terminated = false; // wait for cid to ready, for parent thread to get the cid.
while (!can_run && loop) {
st_usleep( * );
} while (loop) {
if ((ret = handler->on_before_cycle()) != ERROR_SUCCESS) {
srs_warn("thread %s on before cycle failed, ignored and retry, ret=%d", _name, ret);
goto failed;
}
srs_info("thread %s on before cycle success", _name); if ((ret = handler->cycle()) != ERROR_SUCCESS) {
if (!srs_is_client_gracefully_close(ret) && !srs_is_system_control_error(ret)) {
srs_warn("thread %s cycle failed, ignored and retry, ret=%d", _name, ret);
}
goto failed;
}
srs_info("thread %s cycle success", _name); if ((ret = handler->on_end_cycle()) != ERROR_SUCCESS) {
srs_warn("thread %s on end cycle failed, ignored and retry, ret=%d", _name, ret);
goto failed;
}
srs_info("thread %s on end cycle success", _name); failed:
if (!loop) {
break;
} // to improve performance, donot sleep when interval is zero.
// @see: https://github.com/ossrs/srs/issues/237
if (cycle_interval_us != ) {
st_usleep(cycle_interval_us);
}
} // readly terminated now.
really_terminated = true; handler->on_thread_stop();
srs_info("thread %s cycle finished", _name);
}

其核心就是循环调用 变量 ISrsThreadHandler* handler (构造函数的参数赋值进来的)如下三个函数:

virtual int on_before_cycle();
virtual int cycle() = ;
virtual int on_end_cycle();

4. 停止线程循环可以调用 stop_loop() :

void SrsThread::stop_loop()
{
loop = false;
}

但是仔细看使用线程的代码会发现,ISrsThreadHandler* handler 这个变量还是被封装了。

如 SrsOneCycleThread 自己继承自 ISrsThreadHandler

class SrsOneCycleThread : public internal::ISrsThreadHandler
{
private:
internal::SrsThread* pthread;
ISrsOneCycleThreadHandler* handler; //...
}

在new SrsThread 时,将自己的this指针传入,当作SrsThread 的 handler变量,

然后自己的线程函数中重新调用自己的变量: ISrsOneCycleThreadHandler* handler

int SrsOneCycleThread::cycle()
{
int ret = handler->cycle();
pthread->stop_loop();
return ret;
} void SrsOneCycleThread::on_thread_start()
{
handler->on_thread_start();
} int SrsOneCycleThread::on_before_cycle()
{
return handler->on_before_cycle();
} int SrsOneCycleThread::on_end_cycle()
{
return handler->on_end_cycle();
} void SrsOneCycleThread::on_thread_stop()
{
handler->on_thread_stop();
}

注意,虽然 ISrsOneCycleThreadHandlerISrsThreadHandler 这两个接口函数都一样,但是并没有继承关系。

SRS源码—— Thread笔记的更多相关文章

  1. zeromq源码分析笔记之线程间收发命令(2)

    在zeromq源码分析笔记之架构说到了zmq的整体架构,可以看到线程间通信包括两类,一类是用于收发命令,告知对象该调用什么方法去做什么事情,命令的结构由command_t结构体确定:另一类是socke ...

  2. AQS源码阅读笔记(一)

    AQS源码阅读笔记 先看下这个类张非常重要的一个静态内部类Node.如下: static final class Node { //表示当前节点以共享模式等待锁 static final Node S ...

  3. Mina源码阅读笔记(四)—Mina的连接IoConnector2

    接着Mina源码阅读笔记(四)-Mina的连接IoConnector1,,我们继续: AbstractIoAcceptor: 001 package org.apache.mina.core.rewr ...

  4. Hadoop源码学习笔记(4) ——Socket到RPC调用

    Hadoop源码学习笔记(4) ——Socket到RPC调用 Hadoop是一个分布式程序,分布在多台机器上运行,事必会涉及到网络编程.那这里如何让网络编程变得简单.透明的呢? 网络编程中,首先我们要 ...

  5. Hadoop源码学习笔记(3) ——初览DataNode及学习线程

    Hadoop源码学习笔记(3) ——初览DataNode及学习线程 进入了main函数,我们走出了第一步,接下来看看再怎么走: public class DataNode extends Config ...

  6. Hadoop源码学习笔记(2) ——进入main函数打印包信息

    Hadoop源码学习笔记(2) ——进入main函数打印包信息 找到了main函数,也建立了快速启动的方法,然后我们就进去看一看. 进入NameNode和DataNode的主函数后,发现形式差不多: ...

  7. RocketMQ 源码学习笔记————Producer 是怎么将消息发送至 Broker 的?

    目录 RocketMQ 源码学习笔记----Producer 是怎么将消息发送至 Broker 的? 前言 项目结构 rocketmq-client 模块 DefaultMQProducerTest ...

  8. RocketMQ 源码学习笔记 Producer 是怎么将消息发送至 Broker 的?

    目录 RocketMQ 源码学习笔记 Producer 是怎么将消息发送至 Broker 的? 前言 项目结构 rocketmq-client 模块 DefaultMQProducerTest Roc ...

  9. ReentrantReadWriteLock源码分析笔记

    ReentrantReadWriteLock包含两把锁,一是读锁ReadLock, 此乃共享锁, 一是写锁WriteLock, 此乃排它锁. 这两把锁都是基于AQS来实现的. 下面通过源码来看看Ree ...

随机推荐

  1. appium可通过SDK自带的uiautomatorviewer或monitor工具,来查看页面元素(Android)

    工具一:uiautomatorviewer 1.在SDK的tools目录中找到uiautomatorviewer,双击打开若出现闪退一般是jdk版本不匹配(建议安装jdk1.8的): 2.在使用这个工 ...

  2. Android学习09

    SharedPreferences SharedPreferences,是一种轻量级的数据存储方式,采用Key/value的方式 进行映射,Sp通常用于记录一些参数配置.行为标记等! 1.获得mSha ...

  3. django之反向解析和命名空间

    背景:当我们页面中存放的请求路径与url文件中的url一致时,如果url改了是不是所有的请求路径都要跟着改?显然不现实,这里我们就要用到反向解析. 如下图所示,输入url后会跳转到登录页面,输入用户名 ...

  4. SpringBoot与Shiro整合

    一.数据库设计 ​ 这里主要涉及到五张表:用户表,角色表(用户所拥有的角色),权限表(角色所涉及到的权限),用户-角色表(用户和角色是多对多的),角色-权限表(角色和权限是多对多的).表结构建立的sq ...

  5. Bugku-CTF加密篇之散乱的密文(lf5{ag024c483549d7fd@@1} 一张纸条上凌乱的写着2 1 6 5 3 4)

    散乱的密文 lf5{ag024c483549d7fd@@1} 一张纸条上凌乱的写着2 1 6 5 3 4  

  6. 201771010135杨蓉庆 《面向对象程序设计(java)》第三周学习总结

    一:第1-3章学习内容: 第一章:复习基本数据类型 整型 byte(1个字节 表示范围:-2^7 ~ (2^7)-1) short(2个字节 表示范围:-2^15~(2^15)-1) int(4个字节 ...

  7. Java面向对象编程 -1.4

    对象内存分析 对象实例化操作初步分析 Java之中类属于引用数据类型,引用数据类型最大的困难之处在于要进行内存的管理,同时在进行操作的时候也会有内存关系的变化. 所以本次针对于之前的程序的内存关系进行 ...

  8. 5G时代开启,这些新兴职业决定你的后半生

    近段时间,高考志愿填报成为牵动千万家庭的头等大事.事实上,除了学校间的差距外,专业的优劣也在很大程度上决定着人们未来职场生涯的潜力.血淋淋的事实告诉我们,只有选对专业,才能让自己的人生实现升华,并避免 ...

  9. Nginx 七层反向代理

    目录 1.代理 2.正向代理 3.反向代理 4.Nginx 反向代理 5.Nginx 反向代理相关指令介绍 ①.listen ②.server_name ③.location ④.proxy_pass ...

  10. Hibernate面试题(七)--load与get区别

    1. load方式是延迟加载,只有属性被访问的时候才会调用sql语句 get方式是非延迟加载,无论后面的代码是否会访问到属性,马上执行sql语句 2. 都通过id=500去获取对象1. get方式会返 ...