【问题标题】:Is this a C++ Semaphore?这是一个 C++ 信号量吗?
【发布时间】:2016-10-17 10:49:58
【问题描述】:

我有一个线程保存资源(设备的 OpenCl 命令队列),但我想限制同时访问此资源的线程数(如果gpu 命令队列“已满”)。不幸的是,我对 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

}

【问题讨论】:

  • "multi-reader; no writer" - 不需要锁定吗?
  • 目的是限制阅读器的数量。我改变了主题以强调这一点。
  • 那么你想要的是一个信号量。 Here's 一个使用 std::condition 的 impl - 在 C++11 中可用
  • 抱歉,好像是这样。我自己弄糊涂了。

标签: c++ multithreading c++11 atomic


【解决方案1】:

不,这不会像预期的那样运行 - 考虑 2 个线程到达的情况 int cnt = _cnt.load(); 同时。它们都将读取相同的值,并将计数器设置为相同的值,即使可能只有它们中的 1 个应该有。

这可能被认为是您可以忽略的罕见事件,除非您解锁,否则您的计数将变为负数。

【讨论】:

  • 有办法解决吗
  • 尝试 int cnt = ++_cnt 这将保留该值,失败时您可以“解锁”。这也不是完美的,因为如果一个线程尝试锁定,一个解锁,另一个锁定,结果可能是两个线程都无法获得锁,但至少可以确保你永远不会提供锁许多线程。
【解决方案2】:

可能是错字,但你使用 atomic_compare_exchange_weak() 错误

你需要的是

do {
   old=_cnt.load();
   new=old+1;
   if (new > _max_cnt) return false;
} while (!_cnt.compare_exchange_weak(&old,new));

将 obj.compare_exchange_weak(old,new) 想象成一个原子 Compare_And_Swap() 函数

bool Compare_And_Swap() {
    if (obj == old) {
        obj = new;
        return true;
    }
    return false;
}

【讨论】:

    猜你喜欢
    • 2012-08-13
    • 2011-01-15
    • 1970-01-01
    • 2016-10-22
    • 2011-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多