文章目录
WebRTC中将某些功能划分了模块,现在介绍一下模块是如何执行的。WebRTC中会创建一个线程用于执行模块和异步的任务,模块生成以后注册到线程中,模块执行时会计算下次需要执行的时间,线程根据模块提供的时间会按照指定的时间再次调用模块。线程在处理模块的同时也可以处理其他线程投递的任务。
Module使用示例
工程
先创建一个工程用于运行示例。如何创建工程,参考《WebRTC源码分析之工程-project》,在src\examples\BUILD.gn中添加如下内容:
rtc_executable("webrtc_learn"){
testonly = true
sources = [
"webrtclearn/main.cc"
]
deps = [
"../rtc_base:rtc_base",
"../modules/utility:utility"
]
}
示例
#include <iostream>
#include "api/task_queue/queued_task.h"
#include "modules/utility/source/process_thread_impl.h"
#include "modules/include/module.h"
#include "rtc_base/location.h"
using namespace std;
using namespace webrtc;
/*模块一*/
class my_module_one :public Module
{
public:
/*每秒执行一次*/
int64_t TimeUntilNextProcess() { return 1000; }
void Process()
{
static int count = 0;
cout << "process module_one " << count++ << endl;
}
};
/*模块二*/
class my_module_two : public Module
{
public:
/*每两秒执行一次*/
int64_t TimeUntilNextProcess() { return 2000; }
void Process()
{
static int count = 0;
cout << "process module_two " << count++ << endl;
}
};
/*任务*/
class asyn_task : public QueuedTask
{
public:
asyn_task(string task_name)
: task_name_(task_name) {}
bool Run() override
{
cout << "post a " << task_name_ <<endl;
return true;
}
private:
string task_name_;
};
int main()
{
/*创建模块处理对象*/
unique_ptr<ProcessThread> pt = ProcessThread::Create("process thread");
/*定义任务*/
unique_ptr<QueuedTask> task1(new asyn_task("task_one"));
unique_ptr<QueuedTask> task2(new asyn_task("task_two"));
/*定义模块*/
my_module_one mmo;
my_module_two mmt;
/*开始处理任务*/
pt->Start();
/*模块注册*/
pt->RegisterModule(&mmo, RTC_FROM_HERE);
pt->RegisterModule(&mmt, RTC_FROM_HERE);
/*3秒后投递一个即时任务*/
Sleep(3000);
pt->PostTask(std::move(task1));
/*3秒后再投递一个即时任务*/
Sleep(3000);
pt->PostTask(std::move(task2));
/*1秒后注销模块*/
Sleep(1000);
pt->DeRegisterModule(&mmo);
pt->DeRegisterModule(&mmt);
/*关闭模块处理线程,回收资源。*/
pt->Stop();
return 0;
}
向模块处理线程注册了两个模块,其中一个模块一秒执行一次,另外一个模块两秒执行一次。在模块的执行期间向模块处理线程投递了两个异步的任务。
Module源码分析
类关系图
ProcessThread类
ProcessThread类所在文件的位置:src\modules\utility\include\process_thread.h
class ProcessThread
{
public:
virtual ~ProcessThread();
/*用于创建ProcessThread类*/
static std::unique_ptr<ProcessThread> Create(const char* thread_name);
/*创建模块处理线程*/
virtual void Start() = 0;
/*终止模块处理线程,并回收资源。*/
virtual void Stop() = 0;
/*激活模块处理线程,运行指定模块。*/
virtual void WakeUp(Module* module) = 0;
/*向模块处理线程投递任务*/
virtual void PostTask(std::unique_ptr<QueuedTask> task) = 0;
/*模块注册*/
virtual void RegisterModule(Module* module, const rtc::Location& from) = 0;
/*注销模块*/
virtual void DeRegisterModule(Module* module) = 0;
};
Module类
ProcessThread类所在文件的位置:src\modules\include\module.h
class Module
{
public:
/*返回下一次执行Process函数的时间,单位是毫秒。*/
virtual int64_t TimeUntilNextProcess() = 0;
/*模块处理函数*/
virtual void Process() = 0;
/*绑定或者解绑ProcessThread到当前模块*/
virtual void ProcessThreadAttached(ProcessThread* process_thread) {}
protected:
virtual ~Module() {}
};
模块需要继承本接口,覆写指定的函数。
QueuedTask类
QueuedTask类所在文件的位置:src\api\task_queue\queued_task.h
class QueuedTask
{
public:
virtual ~QueuedTask() = default;
virtual bool Run() = 0;
};
所有需要执行的任务都需要继承此类,并覆写Run()函数。
ProcessThreadImpl类
ProcessThreadImpl类所在文件的位置:src\modules\utility\source\process_thread_impl.h process_thread_impl.cc
ModuleCallback类
struct ModuleCallback
{
ModuleCallback() = delete;
ModuleCallback(ModuleCallback&& cb) = default;
ModuleCallback(const ModuleCallback& cb) = default;
/*构造器*/
ModuleCallback(Module* module, const rtc::Location& location)
: module(module), location(location) {}
bool operator==(const ModuleCallback& cb) const
{
return cb.module == module;
}
/*保存的模块*/
Module* const module;
/*模块下次执行时间,绝对时间。*/
int64_t next_callback = 0;
/*模块注册时的位置*/
const rtc::Location location;
private:
ModuleCallback& operator=(ModuleCallback&);
};
对模块的简单封装
数据成员
typedef std::list<ModuleCallback> ModuleList;
/*模块处理线程中注册的模块*/
ModuleList modules_;
/*互斥锁*/
rtc::CriticalSection lock_;
/*记录ProcessThreadImpl对象创建时的线程*/
rtc::ThreadChecker thread_checker_;
/*用于阻塞、唤醒模块处理线程*/
rtc::Event wake_up_;
/*模块处理线程对象,线程句柄。*/
std::unique_ptr<rtc::PlatformThread> thread_;
/*任务队列,保存投递的任务。*/
std::queue<QueuedTask*> queue_;
/*是否结束模块处理线程*/
bool stop_;
/*模块处理线程的名字*/
const char* thread_name_;
构造器与析构器
ProcessThreadImpl::ProcessThreadImpl(const char* thread_name)
: stop_(false), thread_name_(thread_name) {}
std::unique_ptr<ProcessThread> ProcessThread::Create(const char* thread_name)
{
return std::unique_ptr<ProcessThread>(new ProcessThreadImpl(thread_name));
}
ProcessThreadImpl对象的创建可以通过静态成员函数Create()创建。
ProcessThreadImpl::~ProcessThreadImpl()
{
/*需要在主线程中销毁ProcessThreadImpl对象*/
RTC_DCHECK(thread_checker_.IsCurrent());
RTC_DCHECK(!thread_.get());
RTC_DCHECK(!stop_);
/*清空任务队列*/
while (!queue_.empty())
{
delete queue_.front();
queue_.pop();
}
}
模块处理线程的创建与销毁
void ProcessThreadImpl::Start()
{
/*需要在主线程中执行本函数*/
RTC_DCHECK(thread_checker_.IsCurrent());
RTC_DCHECK(!thread_.get());
/*判断是否创建了模块处理线程*/
if (thread_.get())
return;
/*若模块处理线程已经运行则断言失败*/
RTC_DCHECK(!stop_);
/*遍历module列表,将ProcessThreadImpl绑定到模块上。*/
for (ModuleCallback& m : modules_)
m.module->ProcessThreadAttached(this);
/*创建模块处理线程对象*/
thread_.reset(new rtc::PlatformThread(&ProcessThreadImpl::Run, this, thread_name_));
/*创建并运行模块处理线程*/
thread_->Start();
}
创建模块处理线程并运行
void ProcessThreadImpl::Stop()
{
/*只能在主线程销毁模块处理线程*/
RTC_DCHECK(thread_checker_.IsCurrent());
if (!thread_.get())
return;
{
rtc::CritScope lock(&lock_);
/*终止模块处理线程*/
stop_ = true;
}
/*主线程进入阻塞,等待模块处理线程退出。*/
wake_up_.Set();
/*模块处理线程主动终止后,会唤醒主线程回收资源。*/
thread_->Stop();
/*模块处理线程结束后,更改子线程状态。*/
stop_ = false;
/*释放线程对象*/
thread_.reset();
/*遍历module列表,解除绑定到模块上的ProcessThreadImpl。*/
for (ModuleCallback& m : modules_)
m.module->ProcessThreadAttached(nullptr);
}
主线程中主动终止模块处理线程,不能强行终止,需要等待模块处理线程主动退出,在等待的过程中主线程会进入睡眠状态,模块处理线程结束后会唤醒主线程。
模块的注册与注销
void ProcessThreadImpl::RegisterModule(Module* module,const rtc::Location& from)
{
/*模块注册的工作只能在主线程中进行*/
RTC_DCHECK(thread_checker_.IsCurrent());
RTC_DCHECK(module) << from.ToString();
#if RTC_DCHECK_IS_ON
{
rtc::CritScope lock(&lock_);
/*遍历modules_,查看注册模块是否已经存在,不能重复注册。*/
for (const ModuleCallback& mc : modules_)
{
RTC_DCHECK(mc.module != module)
<< "Already registered here: " << mc.location.ToString()
<< "\n"
<< "Now attempting from here: " << from.ToString();
}
}
#endif
/*绑定ProcessThreadImpl到模块中*/
if (thread_.get())
module->ProcessThreadAttached(this);
/*将模块推到modules_中*/
{
rtc::CritScope lock(&lock_);
modules_.push_back(ModuleCallback(module, from));
}
/*唤醒模块处理线程,处理新注册的模块。*/
wake_up_.Set();
}
注册模块时,有可能模块处理线程处于阻塞状态,需要将阻塞的线程唤醒。
void ProcessThreadImpl::DeRegisterModule(Module* module)
{
/*注销模块只能在主线程中进行*/
RTC_DCHECK(thread_checker_.IsCurrent());
RTC_DCHECK(module);
{
rtc::CritScope lock(&lock_);
/*移除指定的模块*/
modules_.remove_if(
[&module](const ModuleCallback& m) { return m.module == module; });
}
/*注销模块中的ProcessThreadImpl*/
module->ProcessThreadAttached(nullptr);
}
注销模块,需要把模块处理线程中的模块移除,同时把模块内的ProcessThreadImpl也移除。
投递任务
void ProcessThreadImpl::PostTask(std::unique_ptr<QueuedTask> task)
{
{
rtc::CritScope lock(&lock_);
/*往任务队列中投递一个任务。*/
queue_.push(task.release());
}
/*唤醒模块处理线程处理任务。*/
wake_up_.Set();
}
模块处理线程不仅仅能处理模块,也可以处理其他线程投递的任务。
执行指定模块
const int64_t kCallProcessImmediately = -1;
用于标识模块需要立即执行
void ProcessThreadImpl::WakeUp(Module* module)
{
{
rtc::CritScope lock(&lock_);
/*遍历modules_列表,找到指定的模块。*/
for (ModuleCallback& m : modules_)
{
if (m.module == module)
/*将模块标识为立即处理*/
m.next_callback = kCallProcessImmediately;
}
}
/*唤醒模块处理线程,有模块需要处理。*/
wake_up_.Set();
}
模块的处理
bool ProcessThreadImpl::Run(void* obj)
{
return static_cast<ProcessThreadImpl*>(obj)->Process();
}
模块处理线程的入口函数
int64_t GetNextCallbackTime(Module* module, int64_t time_now)
{
/*模块下次被调用的时间间隔*/
int64_t interval = module->TimeUntilNextProcess();
/*时间间隔为负数,表示模块需要立即被调用。*/
if (interval < 0)
{
return time_now;
}
return time_now + interval;
}
将模块调用的时间间隔转换为绝对的时间
bool ProcessThreadImpl::Process()
{
TRACE_EVENT1("webrtc", "ProcessThreadImpl", "name", thread_name_);
/*获取当前时间*/
int64_t now = rtc::TimeMillis();
int64_t next_checkpoint = now + (1000 * 60); /*60秒后*/
{
rtc::CritScope lock(&lock_);
/*主线程标识模块处理线程退出时,结束执行,退出线程。*/
if (stop_)
return false;
/*
* 遍历modules_,处理每个module,检查是否到了module的调用时间。
* 到了调用时间的模块,调用模块内的处理函数Process()。
*/
for (ModuleCallback& m : modules_)
{
/*模块首次被调用,计算模块下次调用的绝对时间。*/
if (m.next_callback == 0)
m.next_callback = GetNextCallbackTime(m.module, now);
/* 如果模块的调用时间到了,或者模块被标识为立即调用,
* 则调用模块内的处理函数Process()。*/
if (m.next_callback <= now || m.next_callback == kCallProcessImmediately)
{
{
TRACE_EVENT2("webrtc", "ModuleProcess", "function",
m.location.function_name(), "file",
m.location.file_and_line());
/*调用模块内的处理函数*/
m.module->Process();
}
int64_t new_now = rtc::TimeMillis();
/*模块处理结束后,更新模块下次调用的时间。*/
m.next_callback = GetNextCallbackTime(m.module, new_now);
}
/*找到所模块中最小的下次调用时间*/
if (m.next_callback < next_checkpoint)
next_checkpoint = m.next_callback;
}
/*处理完模块,处理线程的异步任务。*/
while (!queue_.empty())
{
/*任务的处理方式按照FIFO*/
QueuedTask* task = queue_.front();
queue_.pop();
lock_.Leave();
/*处理任务*/
task->Run();
delete task;
lock_.Enter();
}
}
/*计算模块处理线程的阻塞时间*/
int64_t time_to_wait = next_checkpoint - rtc::TimeMillis();
/*若等待时间大于零,则将模块处理线程阻塞指定时间。*/
if (time_to_wait > 0)
wake_up_.Wait(static_cast<int>(time_to_wait));
return true;
}
模块处理线程不仅会处理模块,而且会处理其他线程投递的任务。
小结
本文介绍了模块是如何执行的,关于模块的更多知识需要继续阅读源码。