原子比较交换。这是对的吗?

时间:2014-04-08 20:13:27

标签: multithreading c++11 atomic

我想在某些条件下以原子方式将1添加到计数器中,但我不确定在线程环境中是否正确:

void UpdateCounterAndLastSessionIfMoreThan60Seconds() const {
    auto currentTime = timeProvider->GetCurrentTime();
    auto currentLastSession = lastSession.load();
    bool shouldIncrement = (currentTime - currentLastSession >= 1 * 60);

    if (shouldIncrement) {
        auto isUpdate = lastSession.compare_exchange_strong(currentLastSession, currentTime);
        if (isUpdate) 
            changes.fetch_add(1);
    }
}

private:
    std::shared_ptr<Time> timeProvider;
    mutable std::atomic<time_t> lastSession;
    mutable std::atomic<uint32_t> changes;

如果2个线程同时评估为shouldIncrement = true且isUpdate = true,那么我不想多次递增更改(在这种情况下只有一个应该增加更改)

2 个答案:

答案 0 :(得分:2)

我不是C ++专家,但它看起来像你在评估&#34; isUpdate&#34;之间的竞争条件。并调用&#34; fetch_add(1)&#34;。

所以我认为问题的答案是&#34;这个线程安全吗?&#34;是&#34;不,它不是&#34;。

答案 1 :(得分:1)

至少有点不确定,如下面的场景将显示:

第一个帖子1执行以下操作:

auto currentTime = timeProvider->GetCurrentTime();
auto currentLastSession = lastSession.load();
bool shouldIncrement = (currentTime - currentLastSession >= 1 * 60);

然后线程2执行相同的3个语句,但使得currentTime比线程1 更多。

然后线程1继续更新lastSession的时间,这比线程2的时间短。

然后线程2轮流,但无法更新lastSession,因为线程1已经更改了值。

最终结果是,lastSession已过时,因为线程2无法将其更新为最新值。在所有情况下这可能无关紧要,情况可能很快就会得到解决,但它是一个丑陋的角落,可能会在某处破坏某些假设,如果不是当前的代码,那么在稍后的更改之后。


另一点需要注意的是,lastSessionchnages并非原子级同步。其他线程偶尔会看到已更改的lastSession changes计数器仍未针对该更改进行增加。同样,这可能无关紧要,但很容易忘记这样的事情,并且意外地编写了一些假定它们同步的东西。


我不能立即确定你是否可以通过原子使这100%安全。用互斥体包裹它。

相关问题