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. vue卸载与安装+vue创建项目

    vue卸载 npm uninstall -g vue-cli npm install -g @vue/cli 和 npm install -g @vue/cli-init 命令安装新版本vue-cli ...

  2. esp8266(wifi)模块调试记录

    1.要注意usb转TTL接口上的晶振 如果晶振是12Mhz,可能就收不到反馈,因为12Mhz波特率会有误差.

  3. falsk 使用celery后台执行任务

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

  4. 页面布局 Wrap 组件 和 RaisedButton按钮

    一.RaisedButton 定义一个按钮 Flutter 中通过 RaisedButton 定义一个按钮.RaisedButton 里面有很多的参数,只讲简单的进行使用. return Raised ...

  5. 判断是app 或者 网页

    function openInWebview () { let ua = navigator.userAgent.toLowerCase(); if (ua.match(/MicroMessenger ...

  6. c++写入注册表

    一.说明:      注册表是Windows重要组成部分,注册表记录了大量有关电脑软硬件的信息.注册表中的值通过其名称标识.值名称由与键名相同的字符组成.值本身可以是字符串.二进制数据或者是32位无符 ...

  7. Git基础及进阶-系统总结

    Git基础及进阶-系统总结 by 小强 2019-07-01 考虑到入职后不仅需要熟练掌握git的基本使用,在企业实际操作中还涉及一些进阶指令.作为一个程序员,熟练使用工具是一项基本技能,也是程序员的 ...

  8. Android Studio 使用入门及问题汇总

    声明:转载自http://blog.csdn.net/wei_chong_chong/article/details/56280383 之前一直用eclipse+adt做Android开发.曾经尝试使 ...

  9. Python下opencv使用笔记(十一)(详解hough变换检测直线与圆)

    http://blog.csdn.net/on2way/article/details/47028969 http://blog.csdn.net/mokeding/article/details/1 ...

  10. C语言中的快速排序函数

    C库中有自带的快排函数 qsort() ; 它的函数原型为: void qsort(void * , size_t ,size_t size , int (__cdecl *)(const  void ...