本网站上的一些问题涉及C ++ 11中引入的多线程支持中缺少信号量对象。很多人建议implementing semaphores using mutexes or condition variables or a combination of both。
但是,这些方法都不允许增加和减少信号量,同时保证调用线程不被阻塞,因为通常必须在读取信号量值之前获取锁定。例如,POSIX信号量具有函数sem_post()
和sem_trywait()
,两者都是非阻塞函数。
是否可以仅使用C ++ 11多线程支持实现非阻塞信号量?或者我是否一定要为此使用依赖于操作系统的库?如果是这样,为什么C ++ 11修订版不包含信号量对象?
similar question未在3年内得到答复。 (注意:我相信我要问的问题要广泛得多,除了生产者/消费者之外,还有一些非阻塞信号量对象的其他用途。如果有人认为我的问题是重复的,请告诉我如何我可以回想一下旧问题,因为这仍然是一个悬而未决的问题。)
答案 0 :(得分:3)
我没有看到实现信号量的问题。使用C ++ 11原子和互斥体应该是可能的。
class Semaphore
{
private:
std::atomic<int> count_;
public:
Semaphore() :
count_(0) // Initialized as locked.
{
}
void notify() {
count_++;
}
void wait() {
while(!try_wait()) {
//Spin Locking
}
}
bool try_wait() {
int count = count_;
if(count) {
return count_.compare_exchange_strong(count, count - 1);
} else {
return false;
}
}
};
以下是一个用法示例:
#include <iostream>
#include "Semaphore.hpp"
#include <thread>
#include <vector>
Semaphore sem;
int counter;
void run(int threadIdx) {
while(!sem.try_wait()) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
//Alternative use wait
//sem.wait()
std::cout << "Thread " << threadIdx << " enter critical section" << std::endl;
counter++;
std::cout << "Thread " << threadIdx << " incresed counter to " << counter << std::endl;
// Do work;
std::this_thread::sleep_for(std::chrono::milliseconds(30));
std::cout << "Thread " << threadIdx << " leave critical section" << std::endl;
sem.notify();
}
int main() {
std::vector<std::thread> threads;
for(int i = 0; i < 15; i++) {
threads.push_back(std::thread(run, i));
}
sem.notify();
for(auto& t : threads) {
t.join();
}
std::cout << "Terminate main." << std::endl;
return 0;
}
当然,等待是阻止操作。但是如果比较和交换操作是非阻塞的(可以检查),则notify和try_wait都是非阻塞的。