WebRTC源代码探索之旅——多线程篇(6 - 2)

来源:互联网 发布:php转换特殊字符 编辑:程序博客网 时间:2024/06/05 00:43

6.3 talk_base::Thread

 

talk_base::Thread的主要功能是封装线程,为线程提供消息队列和多路信号分离器的功能。需要注意的是,talk_base::Thread的绝大多数功能是talk_base::MessageQueue和talk_base::PhysicalSocketServer的代码提供的,仅有talk_base::Thread::Send函数的功能主要由talk_base::Thread的代码提供。

 

talk_base::Thread的主要组件包括:

sendlist_:通过talk_base::Thread::Send函数请求处理的消息列表

running_:标示系统线程是否在正在运行的talk_base::Event,该成员变量表示线程正在运行

thread_:保存系统的线程句柄/pthread_t对象

owned_:标示talk_base::Thread对象是否是线程的所有者,该变量的语义和大家的直觉可能很不一样(至少和我的直觉不一样,造成了不少麻烦)。由talk_base::Thread::Start函数启动的系统线程,该成员变量为true;通过talk_base::Thread::WrapCurrent函数包装的线程为false。并不是talk_base::Thread实例对应的哪个线程就占有(own)哪个线程,甚至有些情况下talk_base::Thread实例是唯一的封装系统线程的实例,并通过talk_base::Thread::WrapCurrent设置到了TLS中去,但是这个实例依然不占有系统线程。唯有通过talk_base::Thread::Start函数启动的系统线程,该实例才占有那个系统线程。这个概念很重要,它会影响很多函数的行为。

 

talk_base::Thread的主要成员函数包括:

talk_base::Thread::Current(静态):获取封装当前线程的talk_base::Thread对象,该功能由talk_base::ThreadManager提供

参数说明:无

 

talk_base::Thread::IsCurrent:测试该talk_base::Thread对象是否是封装当前线程的对象。只有在TLS中保存的talk_base::Thread对象才是封装当前线程的对象。在当前线程构造的talk_base::Thread对象不一定是封装当前线程的对象(这点很重要,它将影响多个函数的行为)。

参数说明:无

 

talk_base::Thread::Start:启动线程

参数说明:

runnable:如果为NULL,则调用talk_base::Thread::ProcessMessages函数处理消息循环运行线程;如果不是NULL,则调用runnable->Run运行线程。

 

talk_base::Thread::Stop:停止消息循环,并调用talk_base::Thread::Join等待线程结束

参数说明:无

 

talk_base::Thread::Send:向一个线程发送消息,并等待消息完成,被请求线程可以是当前线程

参数说明:

phandler:消息处理器

id:消息ID

pdata:消息数据

 

talk_base::Thread::Invoke:请求在一个线程上执行函数,被请求的线程可以是当前线程

模板参数说明:

ReturnT:仿函数的返回值类型

FunctorT:仿函数的类型

参数说明:

functor:被请求执行的仿函数

 

talk_base::Thread::Clear:继承自talk_base::MessageQueue::Clear函数,为了保持父类该函数的语义需要同时删除sendlist_列表中的消息

参数说明:

phandler:消息处理器

id:消息ID

pdata:消息数据

 

talk_base::Thread::ReceiveSends:处理Send函数发来的消息

参数说明:无

 

talk_base::Thread::WrapCurrent/UnwrapCurrent:封装/解除封装当前线程,该功能由talk_base::ThreadManager提供

参数说明:无

 

talk_base::Thread::running(私有):线程是否运行。只有使用该实例启动一个系统线程(talk_base::Thread::Start)或者包装一个线程(talk_base::Thread::WrapCurrent)后,该函数才会返回true;

参数说明:无

 

接下来我将简单讲解一下talk_base::Thread的原理。talk_base::Thread的绝大多数功能由talk_base::MessageQueue、talk_base::PhysicalSocketServer和talk_base::ThreadManager类提供。talk_base::Thread的大多数代码是用来实现talk_base::Thread::Send函数的功能。talk_base::Thread::Send函数接受到消息后判断是否当前线程是否就是被请求的线程。如果当前线程即为被请求的线程,立即处理消息。如果当前线程不是被请求线程,将消息加入到被请求线程的talk_base::Thread::sendlist_列表。然后通过talk_base::MessageQueue::ss_->WakeUp函数解除被请求线程的IO阻塞状态,并且通过current_thread->socketserver()->Wait函数让自己等待在IO阻塞中。被请求线程的消息循环talk_base::MessageQueue::Get函数会调用talk_base::Thread::ReceiveSends(虚)函数处理sendlist_中的消息。被请求线程处理完消息后会调用请求线程的thread->socketserver()->WakeUp以解除它的IO阻塞状态。请求线程通过局部变量ready获知被请求线程已经完成了消息处理。整个talk_base::Thread::Send函数在请求线程和被请求线程之间的交互操作流程大致如此。

 

最后,让我们对比下Windows API和Linux API在talk_base::Thread类中的使用状况:

Sleep

nanosleep函数用于将当前线程阻塞等待指定的时间

 

SetThreadPriority

在Linux版本的talk_base::Thread中没有实现该功能

 

CreateThread

pthread_attr_init函数用于初始化pthread的线程属性;pthread_create函数用于创建系统线程

 

修改线程的名字

在Windows平台上使用了一个比较晦涩的方法实现:调用RaiseException(0x406D1388, ... )函数;但是在Linux版本的talk_base::Thread中没有实现该功能(其实这个功能没什么大的作用)。

 

WaitForSingleObject、CloseHandle

pthread_join用于等待系统线程结束。
1 0
原创粉丝点击