Multithreading 原子比较交换。对吗?

Multithreading 原子比较交换。对吗?,multithreading,c++11,atomic,Multithreading,C++11,Atomic,在某些条件下,我想自动向计数器添加1,但我不确定以下内容在线程环境中是否正确: void UpdateCounterAndLastSessionIfMoreThan60Seconds() const { auto currentTime = timeProvider->GetCurrentTime(); auto currentLastSession = lastSession.load(); bool shouldIncrement = (currentTime

在某些条件下,我想自动向计数器添加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;
void updateCounterLastSessionIfMore超过60秒()常量{
自动currentTime=timeProvider->GetCurrentTime();
auto currentLastSession=lastSession.load();
bool shouldIncrement=(currentTime-currentLastSession>=1*60);
如果(应增加){
auto isUpdate=lastSession.compare\u exchange\u strong(currentLastSession,currentTime);
如果(isUpdate)
更改。获取_添加(1);
}
}
私人:
std::共享ptr时间提供者;
可变std::原子lastSession;
可变std::原子变化;

如果2个线程同时评估为SubdPosid= Trand和ISUpUTITY = Tror,我不想多次改变增量(

> P>),我不是C++专家,但我觉得你在“ISUpUPDATE”的评估和调用“FETCHYADD(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%的安全。将其包装到互斥锁中。

如果此线程是正确更新了lastSession(如果正确)的线程,则该线程的fetch_add应该可以。@Ghita是的,但通过“在线程环境中更正”,我将您理解为两个或更多线程可能同时运行的情况。如果线程1和2都在调用fetch_add()之前对isUpdate求值,则两者都将调用fetch_add(),这是您不希望看到的。fetch_add()仅由1个线程执行,因为compare_exchange是一个原子读-修改-写操作是的,在本示例的上下文中,分钟具有误导性。更新了示例代码,但就我所见,
minutes
/
更改将不会被更新,除非
compare\u exchange\u strong
成功。所以它不可能更新太多次。两个线程不能从相同的前一个值更新时间值,因为在原子更新后,另一个线程看到不同的值,更新失败。是的,你是对的,我一开始就在想:-)。更改保证只更新一次在我的情况下,只要正确执行+1(一次),就可以编写可能较旧的lastSession。我认为在并发服务器上不使用锁是合理的,除非有很多线程每秒数百次地调用这些函数,否则我会安全地使用互斥锁。。。您仍然可以使用原子来读取处于一致状态的值,并且只使用互斥来保护修改。好吧,除非如果
lastSession
changes
在原子上不同步是个问题,但这也是当前代码的问题。