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

时间:2023-01-12 13:48:22

6 thread

 

thread.h/thread.cc文件实现了WebRTC对系统线程的封装。它主要包括3个类talk_base::ThreadManager类、talk_base::Thread类和talk_base::Runnalbe类;以及几个工具类talk_base::AutoThread类、talk_base::ComThread类和talk_base::SocketServerScope类。

 

6.1 talk_base::ThreadManager

 

talk_base::ThreadManager类虽然比较复杂,但是它实现的功能还是比较简单的——帮助talk_base::Thread类实现talk_base::Thread::Current静态函数功能。talk_base::Thread::Current静态函数的主要功能就是获取代表当前线程的talk_base::Thread实例。这就要求在创建系统线程的同时能够立即将它自动封装成talk_base::Thread并加以合理地保存。这就是talk_base::ThreadManager的主要功能。

 

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

key_:系统TLS(Thread LocalStorage)的key。在Windows系统上它是一个DWORD变量,在Linux系统上它被定义为pthread_key_t。

TLS能够在线程空间内保存一些数据,所有的线程通过它只能访问到自己线程空间的变量,各个线程之间互不影响。它也是一个重要的多线程编程的工具。到这里talk_base::ThreadManager的基本原理其实已经可以猜得出来了,其实talk_base::ThreadManager就是将封装线程的talk_base::Thread类的实例指针存放在TLS内。线程内运行的代码在调用talk_base::Thread::Current静态函数的时候,talk_base::ThreadManager就从当前线程的TLS内取出该指针并返回。

 

talk_base::ThreadManager的主要函数包括:

talk_base::ThreadManager::WrapCurrentThread:将当前线程封装成一个talk_base::Thread对象,并存储在TLS中。

参数说明:无

 

前面已经提到了talk_base::ThreadManager的基本原理是使用TLS,这里将更具体的讲解它工作的过程。talk_base::ThreadManager本身是一个伪装成singleton的类,但是它没有释放的过程,这个手法在前面的talk_base::PosixSignalHandler中已经讲解过了。talk_base::ThreadManager在构造的时候会将当前线程自动包装成talk_base::Thread。为了达到绝对保证主线程先于其他线程被包装成talk_base::Thread,每个系统线程启动的时候都会在talk_base::Thread::Start函数中调用talk_base::ThreadManager::Instance函数以确认talk_base::ThreadManager实例已经被创建。而在这工程中talk_base::Thread::Start函数是在父线程中被调用的。以上这些保证了在第一次创建子线程之前talk_base::ThreadManager已经在单线程环境中被创建(),并且主线程被封装成talk_base::Thread对象。每个线程的启动函数talk_base::Thread::PreRun函数(在新线程的空间中运行)会调用talk_base::ThreadManager::SetCurrentThread函数将新创建的talk_base::Thread对象放入系统线程的TLS中使它纳入到talk_base::ThreadManager的管理之下。当调用talk_base::ThreadManage::CurrentThread函数时,talk_base::ThreadManager仅仅从TLS中返回代表当前线程的talk_base::Thread对象。

 

对照Windows版和Linux版的代码,我们可以发现2者基本一致。那我们来看一下两者API的对比:

OpenThread、GetCurrentThreadId

pthread_self函数用于获取当前线程的pthread_t。在Windows平台下一般可以使用线程ID或线程句柄代表当前线程,而在Linux平台下使用pthread_t代表当前线程。

 

TlsAlloc

pthread_key_create函数用于创建一个TLS的key

 

TlsGetValue

pthread_getspecific函数用于从TLS中取出数据

 

TlsSetValue

pthread_setspecific函数用于TLS中存放数据

 

TlsFree

pthread_key_delete函数用于删除一个TLS的key

 

6.2 talk_base::Runnalbe

 

该类定义了talk_base::Runnalbe纯虚基类(接口),如果希望定制talk_base::Threaad::Run函数的行为可以继承talk_base::Runnable类,并将实例传递给talk_base::Thread::Start函数