信号量¶
counting_semaphore
是一个轻量同步元件,能控制对共享资源的访问。不同于 std::mutex,counting_semaphore
允许同一资源有多于一个同时访问,至少允许 LeastMaxValue
个同时的访问者。
1 定义¶
counting_semaphore
:实现非负资源计数的信号量binary_semaphore
:仅拥有二个状态的信号量, LeastMaxValue 等于 1,也就是内存的 counter 只有 0 和 1 两种状态。
namespace std {
template<ptrdiff_t LeastMaxValue = /* 实现定义 */>
class counting_semaphore;
using binary_semaphore = counting_semaphore<1>;
}
类模板
namespace std {
template<ptrdiff_t LeastMaxValue = /* 实现定义 */>
class counting_semaphore {
public:
static constexpr ptrdiff_t max() noexcept;
constexpr explicit counting_semaphore(ptrdiff_t desired);
~counting_semaphore();
counting_semaphore(const counting_semaphore&) = delete;
counting_semaphore& operator=(const counting_semaphore&) = delete;
void release(ptrdiff_t update = 1);
void acquire();
bool try_acquire() noexcept;
template<class Rep, class Period>
bool try_acquire_for(const chrono::duration<Rep, Period>& rel_time);
template<class Clock, class Duration>
bool try_acquire_until(const chrono::time_point<Clock, Duration>& abs_time);
private:
ptrdiff_t counter; // 仅用于阐释
};
}
2 方法¶
release
:增加内部计数器并解锁获取者acquire
:减少内部计数器或阻塞到直至能如此try_acquire
:尝试减少内部计数器而不阻塞try_acquire_for
:尝试减少内部计数器,至多阻塞一段时长try_acquire_until
:尝试减少内部计数器,阻塞直至一个时间点
3 示例¶
#include <iostream>
#include <thread>
#include <chrono>
#include <semaphore>
using namespace std::literals;
// 全局二元信号量实例
// 设置对象计数为零
// 对象在未被发信状态
std::binary_semaphore smphSignal(0);
void ThreadProc()
{
// 通过尝试减少信号量的计数等待来自主程序的信号
smphSignal.acquire();
// 此调用阻塞直至信号量的计数被从主程序增加
std::cout << "[thread] Got the signal" << std::endl; // 回应消息
// 等待 3 秒以模仿某种线程正在进行的工作
std::this_thread::sleep_for(3s);
std::cout << "[thread] Send the signal\n"; // 消息
// 对主程序回复发信
smphSignal.release();
}
int main()
{
// 创建某个背景工作线程,它将长期存在
std::jthread thrWorker(ThreadProc);
std::cout << "[main] Send the signal\n"; // 消息
// 通过增加信号量的计数对工作线程发信以开始工作
smphSignal.release();
// release() 后随 acquire() 可以阻止工作线程获取信号量,所以添加延迟:
std::this_thread::sleep_for(50ms);
// 通过试图减少信号量的计数等待直至工作线程完成工作
smphSignal.acquire();
std::cout << "[main] Got the signal\n"; // 回应消息
}
输出:
[main] Send the signal
[thread] Got the signal
[thread] Send the signal
[main] Got the signal