C++ 信号量

C++20 新增了对于信号量的支持,具体参考 

https://zh.cppreference.com/w/cpp/thread/counting_semaphore

template< std::ptrdiff_t LeastMaxValue = /* 由实现定义 */ >
class counting_semaphore;

(1)(C++20 起)

using binary_semaphore = std::counting_semaphore<1>;

(2)(C++20 起)

counting_semaphore 是一个轻量同步原语,能控制对共享资源的访问。不同于 std::mutexcounting_semaphore 允许同一资源进行多个并发的访问,至少允许 LeastMaxValue 个同时的访问者

binary_semaphore 是 std::counting_semaphore 的特化的别名,其 LeastMaxValue 为 1。实现可能将 binary_semaphore 实现得比 std::counting_semaphore 的默认实现更高效

在Visual studio中信号量是使用原子锁来实现的

现在使用锁和信号量手动实现一个信号量

#ifndef __SEMAPHORE_H__
#define __SEMAPHORE_H__

#include <condition_variable>
#include <mutex>
#include <assert.h>

template <int maxValue = INT_MAX>
class Semaphore {
private:
	std::mutex m_mtx;
	std::condition_variable m_cv;
	int m_currCount = 0;

public:
	static constexpr int max() {
		return maxValue; //返回允许的最大值
	}

	Semaphore(int initCount) : m_currCount(initCount) {
		assert(initCount >= 0 && initCount <= max()); //initCount 不能大于 maxValue
	}

	~Semaphore() = default;
	Semaphore(const Semaphore&) = delete;
	Semaphore& operator=(const Semaphore&) = delete;

	void release(int update = 1) {
		if (update == 0) {
			return;
		}
		std::unique_lock<std::mutex> lock(m_mtx);
		assert(update >= 0 && update <= max() - m_currCount);

		m_currCount += update;
		if (m_currCount > 0) {
			m_cv.notify_all();
		}
	}

	void acquire() {
		std::unique_lock<std::mutex> lock(m_mtx);
		m_cv.wait(lock, [this]() { return m_currCount > 0; }); //信号量值小于等于零时阻塞
		m_currCount--;
	}

	bool try_acquire() {
		std::unique_lock<std::mutex> lock(m_mtx);
		if (m_currCount <= 0) {
			return false;
		}
		--m_currCount;
		return true;
	}
};

#endif

相关测试用例

#include "semaphore.h"
#include <thread>
#include <iostream>

void test() {
    using BinarySemaphore = Semaphore<1>;  //重命名信号量

	BinarySemaphore binSem{0};

	auto worker = [](BinarySemaphore &binSemaphore) {
		binSemaphore.acquire();
		std::cout << "worker thread is running\n";
	};

	std::thread workerThread(worker, std::ref(binSem));
	std::cout << "main thread is running\n";

	using namespace std::literals;
	std::this_thread::sleep_for(2s);
	
	binSem.release();
	workerThread.join();
}

int main() {
	test();
	return 0;
}

### C++信号量的用法与实现 在多线程编程中,信号量是一种重要的同步机制,用于控制多个线程对共享资源的访问。C++标准库并未直接提供信号量的支持,但在现代 C++ 中可以通过 `std::counting_semaphore` 或 `std::binary_semaphore` 来实现这一功能(自 C++20 起引入)。如果未使用 C++20,则可以借助第三方库(如 Boost)或其他平台特定 API 实现。 #### 使用 C++20 的信号量 以下是基于 C++20 提供的标准信号量类的一个简单例子: ```cpp #include <semaphore> #include <thread> #include <iostream> void producer(std::counting_semaphore<1> &sema) { std::cout << "Producer is producing...\n"; sema.release(); // 增加计数器 } void consumer(std::counting_semaphore<1> &sema) { sema.acquire(); // 减少计数器并等待可用资源 std::cout << "Consumer consumed.\n"; } int main() { std::counting_semaphore<1> sema(0); // 初始值为 0 std::thread t1(producer, std::ref(sema)); std::thread t2(consumer, std::ref(sema)); t1.join(); t2.join(); return 0; } ``` 上述代码展示了如何通过 `std::counting_semaphore` 控制生产者和消费者之间的同步[^3]。 #### 非 C++20 下的信号量实现 对于不支持 C++20 的环境,可以利用互斥锁和条件变量来模拟信号量的行为。以下是一个简单的手动实现: ```cpp #include <mutex> #include <condition_variable> #include <atomic> class Semaphore { public: explicit Semaphore(int count_ = 0) : count(count_) {} void notify() { std::unique_lock<std::mutex> lock(mutex); ++count; cv.notify_one(); } void wait() { std::unique_lock<std::mutex> lock(mutex); cv.wait(lock, [&]() { return count > 0; }); --count; } private: mutable std::mutex mutex; std::condition_variable cv; int count; }; // 测试函数 void testSemaphore(Semaphore& sema) { sema.wait(); std::cout << "Resource accessed\n"; } int main() { Semaphore sema(2); std::thread threads[5]; for (int i = 0; i < 5; ++i) { threads[i] = std::thread(testSemaphore, std::ref(sema)); } for (auto&& th : threads) { th.join(); } return 0; } ``` 此代码片段展示了一个基本的手动信号量实现及其应用方式[^4]。 #### 平台特定的信号量 除了标准库外,在某些平台上也可以使用操作系统提供的原生信号量接口。例如,在 POSIX 系统上可使用 `sem_t` 和相关函数;而在 Windows 上则有专门的信号量对象可供调用。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值