抓住一个在C ++中只有一次有效的锁

时间:2014-10-28 13:27:52

标签: c++ multithreading c++11 concurrency locking

我正在使用C ++ 11,其中有4个并行插入并发队列的线程。我知道线程何时完成处理,即队列的预期最终大小。

现在,我想对队列内容执行最终聚合操作,该队列内容应严格 仅执行一次。例如,假设我想聚合这些值并将其POST到外部服务。

如何获取仅有效一次的锁定?我不能使用简单的互斥锁,因为这不能保证我只能使用一次。

伪代码:

// inside a thread
enqueue items to concurrent_queue

if(concurrent_queue.size() == EXPECTED_SIZE) {
    // do something ONLY once
}

3 个答案:

答案 0 :(得分:7)

一个简单的解决方案。

if(concurrent_queue.size() == EXPECTED_SIZE) {
    // do something ONLY once
    static bool doItOnce = DoItOnceOnly();
}

答案 1 :(得分:2)

检查Singleton实现的方法。最基本的:

bool executed = false;
void Execute() 
{
    Lock lock;      // scope-based lock, released automatically when the function returns
    if (executed == false) 
    {
       executed = true;
       //.. do computation
    }
}

检查具有原子变量的解决方案和双重检查锁定以获得更好的性能: http://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/

答案 2 :(得分:2)

如果您不担心操作失败的可能性,您只需使用与操作相关联的atomic<bool>即可。所有主题都会尝试使用compare_exchange_strong将标记从false更改为true,但只有一个会成功:

// inside a thread
enqueue items to concurrent_queue

if(concurrent_queue.size() == EXPECTED_SIZE) {
    std::atomic<bool>& flag = retrieve_the_associated_bool();
    bool expected = false;
    if (flag.compare_exchange_strong(expected, true)) {
      // do something
    }
}

如果操作失败,您应该使用std::call_once和与该操作相关联的std::once_flag。其他线程会在尝试“做某事”时等待,并且每个线程依次尝试直到成功:

// inside a thread
enqueue items to concurrent_queue

if(concurrent_queue.size() == EXPECTED_SIZE) {
    std::once_flag& flag = retrieve_the_associated_once_flag();
    std::call_once(flag, []{
        // do something
    });
    // do something ONLY once
}