我想在某些条件下以原子方式将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,那么我不想多次递增更改(在这种情况下只有一个应该增加更改)
答案 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无法将其更新为最新值。在所有情况下这可能无关紧要,情况可能很快就会得到解决,但它是一个丑陋的角落,可能会在某处破坏某些假设,如果不是当前的代码,那么在稍后的更改之后。
另一点需要注意的是,lastSession
和chnages
并非原子级同步。其他线程偶尔会看到已更改的lastSession
changes
计数器仍未针对该更改进行增加。同样,这可能无关紧要,但很容易忘记这样的事情,并且意外地编写了一些假定它们同步的东西。
我不能立即确定你是否可以通过原子使这100%安全。用互斥体包裹它。