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. falsk 使用celery后台执行任务

    # falsk 使用celery后台执行任务 1.基础环境搭建 doc:https://flask.palletsprojects.com/en/1.0.x/patterns/celery/ mkdi ...

  2. Sqoop的安装及常用命令

    本次安装主要是为了离线分析数据清洗完成后的操作:网站日志流量分析系统之数据清洗处理(离线分析) 一.概述 1. sqoop是Apache 提供的工具,用于hdfs和关系型数据库之间数据的导入和导入 2 ...

  3. 关于null和空指针异常

    1,null是一个标识符,用来表示不确定的对象,可以将null赋给引用类型变量,但不可以将null赋给基本类型变量 2,null本身不是对象,也不是object的实例,也不知道是什么类型 3,对于集合 ...

  4. 20 JavaScript随机&逻辑&比较&类型转换

    JavaScript 随机 Math.random(): 返回0~1之间的随机数,包括0不包括1 Math.floor():下舍入.Math.floor(2.9) = 2.Math.floor(Mat ...

  5. CPI 3.0磁盘空间不足!

    当使用Cisco PI的时候,有的时候可能出现diskspace不够的情况,这种情况可能是前期部署PI的时候,提供的空间太小了,或者目前缓存的数据太多了. 如下是一个例子: 在CLI中检查时,PI数据 ...

  6. Cisco AP-如何调整LAP信道

    GUI方法: CLI的方法:根据对应的接口去调整信道,信道带宽,传输功率等信息吧.(Cisco Controller) >config slot 0 antenna Configures the ...

  7. from flyai.dataset import Dataset 报错

    from flyai.dataset import Dataset 报错 No module name 'flyai' ​ 先找到ide中使用的Python对应的pip的位置. ​ windows用户 ...

  8. OpenThreads库学习

    在看STM32资料中看到STM32WB系列“双核无线微控制器配备双核无线微控制器(MCU)配备Bluetooth® 5.OpenThread和ZigBee®3.0连接技术,同时兼备超低功耗性能“不知道 ...

  9. 安装mysql常见错误解决方法

    Mysql ERROR 1698 (28000) 解决 解决mysqld_safe Directory '/var/run/mysqld' for UNIX socket file don't exi ...

  10. Linux Mysql基础操作

    1). 打开MySQL 使用如下两条命令,打开MySQL服务并使用root用户登录: # 启动 MySQL 服务 sudo service mysql start # 使用 root 用户登录,实验楼 ...