Webrtc 多線程模塊主要涉及 criticalsection、event、messagequeue、thread、messagehandler、physicalsocketserver 等文件. 注意 webrtc 最新的代碼將 base 目錄改為了 rtc_base。
Event
文件路徑 webrtc/base/event.h webrtc/base/event.c.
event.h/event.cc文件中在 namespace rtc 中, 只有class Event類。
該類主要實現了跨平臺的Win32 Event功能。Event類的各個成員函數與Win32 Event所提供的API幾乎一致。
在 Linux 系統中,WebRTC 使用了mutex和條件變量來實現Event的功能。首先,對Win 32 API和pthread API做一下類比:
- CreateEvent
pthread_mutex_init、pthread_cond_init這兩個函數用來創建pthread的mute和條件變量。
- CloseHandle
pthread_mutex_destroy、pthread_cond_destroy這兩個函數用來銷毀pthread的mute和條件變量。
- SetEvent
pthread_mutex_lock、pthread_mutex_unlock這兩個函數加鎖和解鎖mutex,
pthread_cond_broadcast函數用來解除所有等待在該條件變量上的線程的阻塞狀態。
- ResetEvent
pthrea_mutex_lock、pthread_mutex_unlock(已解釋)
- WaitForSingleObject
pthrea_mutex_lock、pthread_mutex_unlock(已解釋)。pthrea_cond_wait函數用來使線程阻塞在條件變量上。
下面將大致解釋一下 Event 類的實現原理:
Event的主要功能由條件變量實現,mutex只是輔助條件變量起到鎖的作用。條件變量的 pthread_cond_wait 和pthread_cond_broadcast函數與Win32 Event的WaitForSingleObject和SetEvent基本類似。Event是否為signal狀態由布爾類型的成員變量event_status_控制。是否為manual reset的Event由布爾類型的成員變量is_manual_reset_控制。與Win32 Event不同的狀況主要體現在Event的manual reset控制上。
linux 系統下所有調用 Event::Wait 函數的線程會阻塞在pthread_cond_wait 函數上。當 Event::Set 函數被調用時,pthread_cond_broadcast 函數會解除所有等待在 pthread_cond_wait 函數上的線程的阻塞狀態。這對于 manual reset 的 Win32 Event 來說沒什么問題,問題出在 auto reset 的 Win32 Event 上。Auto reset 的 Win32 Event 每次只能解除一條等待在Event上的線程的阻塞狀態,其他線程依然為阻塞狀態。這就需要mutex來配合實現了。
在這里要重點解釋一下 pthread_cond_wait 函數的第二個參數 pthread_mutex_t *mutex。當線程進入pthread_cond_wait 函數時會解鎖 mutex,而在離開 pthread_cond_wait 時會重新加鎖 mutex。可以理解為:
intpthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex)
{
pthread_mutex_unlock(mutex);
…
…
…
pthread_mutex_lock(mutex);
return0;
}
這是 Win32 沒有的行為,需要特別注意。
有了以上的機制后,模擬 auto rest的 Win32 Event 就沒問題了。當第一條線程獲得 mutex 鎖并離開pthread_cond_wait 函數時,其他線程會依然被阻塞在 pthread_mutex_lock(mutex) 函數上,無法離開 pthread_cond_wait 函數。那條成功離開線程會馬上檢測當前的 Event 是否為 manual reset 的,如果不是就馬上將 event_status_ 成員變量設置為 false,并解鎖 mutex。這時其他線程才能有機會離開pthread_cond_wait 函數。不過當他們離開 pthread_cond_wait 后立即檢測 event_status_ 成員變量,如果為 false 就重新調用 pthread_cond_wait 函數。這就完美實現了 Win32 Event 的 auto reset 的語義。
條件變量和 mutex 的配合是 Event 類的難點。如果讀者還是不能完全理解,請仔細閱讀以上 3 段的內容(也可以上網查找 pthread_cond_wait 函數),并結合 event.cc 的源代碼反復揣摩,應該可以很快理解的(畢竟代碼不多,而且也不是WebRTC中真正困難的部分)