C++通过C库或互斥和条件变量实现信号量

C++利用互斥和条件变量实现信号量

信号量是用来实现对共享资源的同步访问机制,其使用方法和条件变量类似,都是通过主动等待和主动唤醒来实现的。

C++标准库中并没有信号量的实现和封装,我们可以用C语言提供的<semaphore.h>

C提供的库<semaphore.h>详解和使用

一、函数简介
信号量的数据类型为结构sem_t,它本质上是一个长整型的数。函数sem_init()用来初始化一个信号量。它的原型为:  

extern int sem_init __P ((sem_t *__sem, int __pshared, unsigned int __value));  

sem为指向信号量结构的一个指针;pshared不为0时此信号量在进程间共享,否则只能为当前进程的所有线程共享;value给出了信号量的初始值。  

(1)函数sem_post( sem_t *sem )用来增加信号量的值。当有线程阻塞在这个信号量上时,调用这个函数会使其中的一个线程不在阻塞,选择机制同样是由线程的调度策略决定的。  

(2)函数sem_wait( sem_t *sem )被用来阻塞当前线程直到信号量sem的值大于0,解除阻塞后将sem的值减一,表明公共资源经使用后减少。函数sem_trywait ( sem_t *sem )是函数sem_wait()的非阻塞版本,它直接将信号量sem的值减一。  

(3)函数sem_timedwait(sem_t *sem, const struct timespec *abs_timeout) 与 sem_wait() 类似,只不过 abs_timeout 指定一个阻塞的时间上限,如果调用因不能立即执行递减而要阻塞。

(4)函数sem_destroy(sem_t *sem)用来释放信号量sem。 

#include <semaphore.h> //先引入库

class Foo {
private:
    sem_t sem_1, sem_2; //定义需要的信号量

public:
    Foo() {
        sem_init(&sem_1, 0, 0), sem_init(&sem_2, 0, 0); //初始化信号量
    }

    void first(function<void()> printFirst) {
        printFirst();
        sem_post(&sem_1); //v操作,使变量加1
    }

    void second(function<void()> printSecond) {
        sem_wait(&sem_1);
        printSecond();
        sem_post(&sem_2);
    }

    void third(function<void()> printThird) {
        sem_wait(&sem_2);
        printThird();
    }
};

互斥和条件变量实现信号量

1、信号量

信号量是一个整数count,提供两个原子(atom,不可分割)操作:P操作和V操作

  • P操作(wait操作):count减1;如果 count < 0 那么挂起执行的线程
  • V操作(signal操作):count加1;如果 count <= 0 那么唤醒一个执行线程

2、信号量实现(定义一个类)

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std;

class semaphore
{
public:
	semaphore(int value = 1) : count(value) {}

	void wait()
	{
		unique_lock<mutex> lck(mtx);
		if (--count < 0) //资源不足挂起线程
			cv.wait(lck); //第一次调用时后面第二个参数默认为false,之后为true
	}

	void signal()
	{
		unique_lock<mutex> lck(mtx);
		if (++count <= 0) //有线程挂起,唤醒一个
			cv.notify_one();
	}

private:
	int count;
	mutex mtx;
	condition_variable cv;
};

3.利用信号量解决吃水果问题

  吃水果问题:桌子有一只盘子,只允许放一个水果,父亲专向盘子放苹果,母亲专向盘子放桔子 儿子专等吃盘子的桔子,女儿专等吃盘子的苹果。只要盘子为空,父亲或母亲就可以向盘子放水果, 仅当盘子有自己需要的水果时,儿子和女儿可从盘子取出。请给出四个人之间的同步关系,并用 pv操作实现四个人的正确活动的问题。

semaphore plate(1), apple(0), orange(0);

void father()
{
	while (true) {
		plate.wait();
		cout << "往盘中放一个苹果" << endl;
		apple.signal();
	}
}

void mother()
{
	while (true) {
		plate.wait();
		cout << "往盘中放一个橘子" << endl;
		orange.signal();
	}
}

void son()
{
	while (true) {
		orange.wait();
		cout << "儿子吃橘子" << endl;
		plate.signal();
	}
}

void daughter()
{
	while (true) {
		apple.wait();
		cout << "女儿吃苹果" << endl;
		plate.signal();
	}
}

int main()
{
	thread f(father), m(mother), s(son), d(daughter);
	f.join();
	m.join();
	s.join();
	d.join();
	return 0;
}
posted @ 2021-07-30 17:13  hellogiao1  阅读(880)  评论(0)    收藏  举报