std::condition_variables 可以用作计数信号量吗?
Can std::condition_variables be used as counting semaphores?
这是 的后续。
std::condition_variable 对象可以用作计数信号量吗?
我认为不是因为该对象似乎绑定到 std::mutex,这意味着它只能用作二进制信号量。我在网上看过,包括 here, here, and here,但找不到使用这些对象作为计数信号量的参考或示例。
是的。
struct counting_sem {
counting_sem(std::ptrdiff_t init=0):count(init) {}
// remove in C++17:
counting_sem(counting_sem&& src) {
auto l = src.lock(); // maybe drop, as src is supposed to be dead
count = src.count;
}
counting_sem& operator=(counting_sem&& src) = delete;
void take( std::size_t N=1 ) {
if (N==0) return;
auto l = lock();
cv.wait(l, [&]{
if (count > 0 && count < (std::ptrdiff_t)N) {
N -= count;
count = 0;
} else if (count >= (std::ptrdiff_t)N) {
count -= N;
N = 0;
}
return N == 0;
});
}
void give( std::size_t N=1 ) {
if (N==0) return;
{
auto l = lock();
count += N;
}
cv.notify_all();
}
// reduce the count without waiting for it
void reduce(std::size_t N=1) {
if (N==0) return;
auto l = lock();
count -= N;
}
private:
std::mutex m;
std::condition_variable cv;
std::ptrdiff_t count;
auto lock() {
return std::unique_lock<std::mutex>(m);
}
auto unlocked() {
return std::unique_lock<std::mutex>(m, std::defer_lock_t{});
}
};
代码未经测试或编译,但设计合理。
take(7)
不等同于 for(repeat 7 times) take()
:相反,如果不够,它会尽可能多地阻塞。
修改以使其在足够的情况下不采取任何措施很容易:
if (count >= (std::ptrdiff_t)N) {
count -= N;
N = 0;
}
这是
std::condition_variable 对象可以用作计数信号量吗?
我认为不是因为该对象似乎绑定到 std::mutex,这意味着它只能用作二进制信号量。我在网上看过,包括 here, here, and here,但找不到使用这些对象作为计数信号量的参考或示例。
是的。
struct counting_sem {
counting_sem(std::ptrdiff_t init=0):count(init) {}
// remove in C++17:
counting_sem(counting_sem&& src) {
auto l = src.lock(); // maybe drop, as src is supposed to be dead
count = src.count;
}
counting_sem& operator=(counting_sem&& src) = delete;
void take( std::size_t N=1 ) {
if (N==0) return;
auto l = lock();
cv.wait(l, [&]{
if (count > 0 && count < (std::ptrdiff_t)N) {
N -= count;
count = 0;
} else if (count >= (std::ptrdiff_t)N) {
count -= N;
N = 0;
}
return N == 0;
});
}
void give( std::size_t N=1 ) {
if (N==0) return;
{
auto l = lock();
count += N;
}
cv.notify_all();
}
// reduce the count without waiting for it
void reduce(std::size_t N=1) {
if (N==0) return;
auto l = lock();
count -= N;
}
private:
std::mutex m;
std::condition_variable cv;
std::ptrdiff_t count;
auto lock() {
return std::unique_lock<std::mutex>(m);
}
auto unlocked() {
return std::unique_lock<std::mutex>(m, std::defer_lock_t{});
}
};
代码未经测试或编译,但设计合理。
take(7)
不等同于 for(repeat 7 times) take()
:相反,如果不够,它会尽可能多地阻塞。
修改以使其在足够的情况下不采取任何措施很容易:
if (count >= (std::ptrdiff_t)N) {
count -= N;
N = 0;
}