C++20 新增了对于信号量的支持,具体参考
https://zh.cppreference.com/w/cpp/thread/counting_semaphore
template< std::ptrdiff_t LeastMaxValue = /* 由实现定义 */ > | (1) | (C++20 起) |
using binary_semaphore = std::counting_semaphore<1>; | (2) | (C++20 起) |
counting_semaphore
是一个轻量同步原语,能控制对共享资源的访问。不同于 std::mutex,counting_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;
}