C++ 这是C++;信号灯?

C++ 这是C++;信号灯?,c++,multithreading,c++11,atomic,C++,Multithreading,C++11,Atomic,我有一个线程保存资源(设备的OpenCl命令队列),但我想限制同时访问此资源的线程数(如果gpu命令队列“已满”,我想在cpu上计算)。不幸的是,我对c++11原子操作还比较陌生。所以我想知道下面的源代码是否按预期工作 class SpinSemaphore{ public: SpinSemaphore(int max_count): _cnt(0), _max_cnt(max_count){} bool try_lock(){ boo

我有一个线程保存资源(设备的OpenCl命令队列),但我想限制同时访问此资源的线程数(如果gpu命令队列“已满”,我想在cpu上计算)。不幸的是,我对c++11原子操作还比较陌生。所以我想知道下面的源代码是否按预期工作

class SpinSemaphore{
public:
    SpinSemaphore(int max_count):
       _cnt(0),
       _max_cnt(max_count){}

    bool try_lock(){
       bool run = true;
       while(run){
           int cnt = _cnt.load();
           if(++cnt > _max_cnt) return false;

           run = !std::atomic_compare_exchange_weak(&_cnt, &cnt,
            std::memory_order_acquire);
       }
       return true;
   }

void unlock(){
    --_cnt;
}

private:
   std::atomic<int>     _cnt;
   int              _max_cnt;
};

//

SpinSemaphore m(4);

void foo(){ //..
   if(m.try_lock()){//..
      my_queue.enqueueNDRangeKernel(/**/);
   }
   else
       //fallback

}
类自旋信号量{
公众:
自旋信号量(int max_count):
_碳纳米管(0),
_max_cnt(max_count){
bool try_lock(){
bool run=true;
while(运行){
int cnt=_cnt.load();
如果(++cnt>\u max\u cnt)返回false;
run=!std::原子比较交换弱,
std::存储器(顺序获取);
}
返回true;
}
无效解锁(){
--_碳纳米管;
}
私人:
std::原子碳纳米管;
int_max_cnt;
};
//
自旋信号量m(4);
void foo(){/。。
如果(m.try_lock()){/。。
my_queue.enqueueNDRangeKernel(/**/);
}
其他的
//退路
}

< /代码>

不,这不会像预期的那样行动——考虑2个线程到达的情况。

int cnt=_cnt.load()同时。它们都将读取相同的值,并且都将计数器设置为相同的值,即使它们中可能只有一个应该得到相同的值


这可能被认为是一个可以接受的罕见事件,你可以忽略,除了当你解锁,你的计数将变成负数

可能是因为输入错误,但您使用原子\u比较\u交换\u弱()是错误的

你需要的是

do {
   old=_cnt.load();
   new=old+1;
   if (new > _max_cnt) return false;
} while (!_cnt.compare_exchange_weak(&old,new));
将obj.compare_exchange_weak(旧的、新的)想象成一个原子-compare_和-Swap()函数


“多读卡器;无写卡器”-不需要锁定,然后就可以了?目的是限制读卡器的数量。我把话题改成在下面划线,然后你要的是一个信号灯。一个使用std::condition的impl——在C++11中是可用的——很抱歉,看起来是这样的。我弄糊涂了。有没有办法修复ittry int cnt=++\u cnt,它将保留该值,如果失败,您可以“解锁”。这也不是完美的,因为如果一个线程尝试锁定,一个线程解锁,另一个线程锁定,结果可能是两个线程都无法获得锁,但它至少可以确保您不会向太多线程提供锁。
bool Compare_And_Swap() {
    if (obj == old) {
        obj = new;
        return true;
    }
    return false;
}