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_);

扫描二维码关注公众号,回复: 4635949 查看本文章

等待一定的时间,如果再等待时间内,条件还没成立,那么就直接返回
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去通知,可以从结果很明显的看到,线程四在收到通知后,是立刻就退出来了.

猜你喜欢

转载自blog.csdn.net/zhangkai19890929/article/details/85108786