Linux C++ 執行緒同步鎖和wait()/broadcast()功能(二)
在第一篇中,我們講解了linux下鎖的概念:
https://blog.csdn.net/zhangkai19890929/article/details/85107046
這一篇我們主要講解wait()和broadcast的 知識:
首先我們需要介紹的是:
pthread_cond_t代表一個條件變數,pthread_mutex_t代表互斥鎖,條件變數要配合互斥鎖來完成。
線上程中,條件變數主要有2個比較大的動作:
1.執行緒等待"條件成立"而掛起
2.另一個執行緒使"條件成立"
因為同一時間我們只能滿足一個 執行緒等待"條件成立" ,為了防止競爭,我們總是和一個互斥鎖配合使用.
接下來我們來講解實現原理:
1.建立條件變數,並進行初始化
pthread_cond_t event_cond_;
pthread_cond_init(&event_cond_,NULL);
2.等待條件成立的2種方式
永遠等待:
error = pthread_cond_wait(&event_cond_,&event_mutex_);
等待一定的時間,如果再等待時間內,條件還沒成立,那麼就直接返回
error = pthread_cond_timedwait(&event_cond_, &event_mutex_,&ts);
3.啟用條件的方式
pthread_cond_signal()啟用一個等待條件的執行緒.
pthread_cond_broadcast()啟用所有的等待執行緒.
接下來我們看看webrtc中的功能實現:
event.h標頭檔案
#include <pthread.h> class Event { public: static const int kForever = -1; Event(bool manual_reset,bool initially_signaled); ~Event(); void Set(); void Reset(); bool Wait(int milliseconds); private: pthread_mutex_t event_mutex_; //互斥鎖 pthread_cond_t event_cond_;//條件變數 const bool is_manual_reset_; bool event_status_; }; #endif
event.cpp 檔案的實現:
class EventWrapperImpl : public EventWrapper {
public:
EventWrapperImpl() : event_(false,false) {}
~EventWrapperImpl() {}
bool Set() override {
event_.Set();
return true;
}
EventTypeWrapper Wait(unsigned long max_time) override {
int to_wait = max_time == 0xffffffff ? Event::kForever : static_cast<int>(max_time);
return event_.Wait(to_wait) ? kEventSignaled : kEventTimeout;
}
private:
Event event_;
};
EventWrapper* EventWrapper::Create() {
return new EventWrapperImpl();
}
Event::Event(bool manual_reset, bool initially_signaled)
: is_manual_reset_(manual_reset),
event_status_(initially_signaled)
{
pthread_mutex_init(&event_mutex_,NULL);
pthread_cond_init(&event_cond_,NULL);
}
Event::~Event() {
pthread_mutex_destroy(&event_mutex_);
pthread_cond_destroy(&event_cond_);
}
void Event::Set() {
pthread_mutex_lock(&event_mutex_);
event_status_ = true;
pthread_cond_broadcast(&event_cond_);
pthread_mutex_unlock(&event_mutex_);
}
void Event::Reset() {
pthread_mutex_lock(&event_mutex_);
event_status_ = false;
pthread_mutex_unlock(&event_mutex_);
}
bool Event::Wait(int milliseconds) {
pthread_mutex_lock(&event_mutex_); //必須先獲取鎖,避免競爭狀態
int error = 0;
if (milliseconds != kForever)
{
struct timespec ts;
struct timeval tv;
gettimeofday(&tv,NULL);
ts.tv_sec = tv.tv_sec + (milliseconds / 1000);
ts.tv_nsec = tv.tv_usec * 1000 + (milliseconds % 1000) * 1000000;
//Handler overflow
if (ts.tv_nsec >= 1000000000)
{
ts.tv_sec++;
ts.tv_nsec -= 1000000000;
}
while (!event_status_ && error == 0) {
error = pthread_cond_timedwait(&event_cond_, &event_mutex_,&ts); //同時會釋放出鎖event_mutex_,所以在此之前,此執行緒必須先獲取到鎖.
}
}
else
{
//永遠等待
while (!event_status_ && error == 0) {
error = pthread_cond_wait(&event_cond_,&event_mutex_);
}
}
if (error == 0 && !is_manual_reset_)
event_status_ = false;
return error == 0;
}
OK,在main方法中,我們來實現:
void* thread4(void * client)
{
cout << "thread4 Wait 5 seconds" << endl;
EventWrapper* event = (EventWrapper *) client;
event->Wait(5000);
cout << "thread4 Wait success" << endl;
}
void* thread5(void * client)
{
cout << "thread5 broadcast" << endl;
EventWrapper* event = (EventWrapper *)client;
event->Set();
}
這裡我先讓執行緒4暫停5秒,然後讓線上程5去通知,可以從結果很明顯的看到,執行緒四在收到通知後,是立刻就退出來了.