1. 程式人生 > >Linux C++ 執行緒同步鎖和wait()/broadcast()功能(二)

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去通知,可以從結果很明顯的看到,執行緒四在收到通知後,是立刻就退出來了.