C++11实现信号量及其在生产-消费者模型中的应用

本文详细探讨了如何在C++11中利用新特性实现信号量,包括互斥锁、条件变量等关键概念,通过实例解析其在多线程同步中的重要作用。了解并掌握C++11信号量的使用,将有助于提升并发编程的效率和安全性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 一、引言

在多线程编程中,信号量(Semaphore)是一种重要的同步机制,用于控制对共享资源的访问。虽然C++标准库中没有直接提供信号量类,但我们可以利用C++11引入的<mutex><condition_variable>来实现一个高效的信号量。本文将详细介绍信号量的实现原理,并展示如何使用它构建经典的生产者-消费者模型。

二、信号量的基本概念

信号量是一种计数器,用于控制多个线程对共享资源的访问。它主要有两种操作:

  1. ​Wait()​​ (也称为P操作):当信号量值大于0时,线程可以继续执行并将信号量减1;否则线程被阻塞;
  2. ​Signal()​​ (也称为V操作):释放资源,将信号量值加1并唤醒等待的线程。

三、C++11信号量实现

头文件设计

// CSemaphore.h

#pragma once

#include <mutex>
#include <condition_variable>

class CSemaphore {
public:
	explicit CSemaphore(long count = 0); // 使用explicit防止隐式转换
	void Signal(); // V操作
	void Wait(); // P操作

private:
	std::mutex mutex_; // 互斥锁保护计数器
	std::condition_variable cv_; // 条件变量用于线程等待
	long count_; // 信号量计数器
};

实现细节

// CSemaphore.cpp

#include "CSemaphore.h"

// 构造函数初始化计数器
CSemaphore::CSemaphore(long count) :count_{count} {}

// Signal操作:增加计数器并通知一个等待线程
void CSemaphore::Signal() {
	std::unique_lock<std::mutex> lock(mutex_);
	++count_;
	cv_.notify_one(); // 通知一个等待线程
}

// Wait操作:等待直到计数器大于0,然后减少计数器
void CSemaphore::Wait() {
	std::unique_lock<std::mutex> lock(mutex_);
    // 使用条件变量等待,直到count_ > 0
	cv_.wait(lock, [=] {return m_count > 0; });
	--count_;
}

实现要点说明

  1. ​线程安全​​:使用std::mutex保护对count_的访问,防止竞态条件;
  2. ​条件变量​​:std::condition_variable用于高效地等待信号量变为正数;
  3. ​RAII​​:std::unique_lock自动管理锁的生命周期;
  4. ​虚假唤醒​​:条件变量的wait方法包含谓词检查,防止虚假唤醒。

四、生产者-消费者模型应用

下面展示如何使用我们实现的信号量构建一个生产者-消费者模型,解决经典的线程同步问题。

全局定义

#include "CSemaphore.h"
#include <iostream>

constexpr int BufferSize = 128; // 缓冲区大小
constexprint DataSize = 500; // 生产/消费数据总量

int buff[BufferSize]; // 共享缓冲区
CSemaphore freeSpace(BufferSize); // 空闲空间信号量(初始为缓冲区大小)
CSemaphore usedSpace(-100); // 已用空间信号量(初始为0)

 生产者线程

void producer() {
	for (int i = 0; i < DataSize; ++i) {
		freeSpace.Wait(); // 等待有空闲空间

        // 生产数据
		std::thread::id thread_id = std::this_thread::get_id();
		buff[i%BufferSize] = i;
		printf("Thread %d,生产 %d\n", thread_id, i);

		usedSpace.Signal(); // 通知有数据可用
		std::this_thread::sleep_for(std::chrono::milliseconds(50));
	}
}

 消费者线程

void consumer() {
	for (int i = 0; i < DataSize; ++i) {
		usedSpace.Wait(); // 等待有数据可用

        // 消费数据
		std::thread::id thread_id = std::this_thread::get_id();
		printf("Thread %d,消费的数字 %d\n", thread_id, buff[i%BufferSize]);

		freeSpace.Signal(); // 通知有空闲空间
	}
}

 主函数

int main() {
	std::thread threads1(producer);
	std::thread threads2(consumer);

	threads1.join();
	threads2.join();
	std::cout << "完成!" << std::endl;

	std::cin.get();
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值