比较是原子操作吗?

| 以下比较是原子动作吗?即可以将其简化为一条CPU指令吗?
char flag = 2;

for(;;)
{
    if (!flag) // <-- this
        break;

    // sleep
}
这是我正在做的事情:
int main()
{
    sf::Mutex Mutex;
    char flag = 2;

    coordinatorFunction(flag);

    for(;;)
    {
        if (!flag)
            break;

        // sleep
    }
}

void workerFunction(void* a)
{
    char* p = static_cast<char*>(a);

    // work

    GlobalMutex.Lock();
    --*p;
    GlobalMutex.Unlock();
}

void coordinatorFunction(char& refFlag)
{
    sf::Thread worker1(&workerFunction, &refFlag);
    sf::Thread worker2(&workerFunction, &refFlag);

    worker1.Launch();
    worker2.Launch();
}
    
已邀请:
这是错误的解决方法。 您的主线程正在尽可能快地消耗CPU周期,除了等待
flag
达到零外,什么也没做。每次尝试都会失败,最后一次除外。与其以这种方式进行操作,不如使用\“ join \”工具,您的线程对象很可能必须使主线程挂起自身,直到所有工作程序完成。 这样,并非偶然,您将不会在乎测试是否是原子性的,因为您根本不需要它。     
C ++操作均不能保证是原子操作。     
在C ++中,没有任何东西可以保证是原子的。     
不。据我所知,C ++不保证什么是原子的,什么不是原子的-那是特定于平台的。即使您的平台保证可以进行原子比较,也不能保证C ++编译器会选择该指令。 但是,实际上,对简单值类型(例如char,int,float等)的比较可能是原子的。但是,您仍然需要注意在编译器级别和处理器级别可能对指令进行的重新排序。在这种情况下,这可能并不重要,但是在一般情况下,它可以并且可以。您还需要注意,即使比较是比较,然后分支也不是原子的-因此,如果您尝试使用标志来调节访问,则两个线程都可以输入相同的代码块。 如果您需要适当的保证,则Windows上有各种互锁功能,而gcc上有原子内建函数。     
不,C ++不保证任何操作都是原子操作。您问题中的代码很可能会被编译为从内存到寄存器的加载,而寄存器本身可能会接受多个指令,然后进行测试。     
这种比较不是原子的,因为它需要花一些机器语言指令来完成(将内存中的内容加载到寄存器等中)。此外,由于内存模型的灵活性和缓存测试线程可能无法“看到”测试结果马上有另一个线程。 如果变量标记为volatile,则可以安全地进行简单测试,但这将是特定于平台的。正如其他人指出的那样,C ++本身对此不做任何保证。     
没有。 比较包括读取两条数据以及执行实际比较。数据可以在读取和比较指令之间改变,因此不是原子的。 但是,由于要进行相等性比较,因此
_InterlockedCompareExchange
内在指令(用于x86中的
lock cmp xchg
指令)可能会满足您的需要,尽管它将涉及替换数据。     
您应该问的问题是“是-原子”?多数民众赞成在这里重要。当标志到达0时,您想做一些事情。 您不关心这种情况:
1. Main thread reads flag, and it is 1.
2. Worker changes flag with --
3. Main thread doesn\'t see that flag is actually 0.
因为在1 ns内,主线程会循环并重试。 您确实要注意-不是原子的,并且同时更改它的两个线程将跳过减量:
1. Thread A reads flag, flag is 2
2. Thread B reads flag, flag is 2
3. Thread A decrements its copy of flag, 2, and writes to flag, flag is 1
4. Thread B decrements its copy of flag, also 2, and writes to flag, flag is 1.
您输了一个减量。您想使用__sync_fetch_and_sub(&flag,1),它将自动减少标记。 最后,在睡眠中旋转并不是最好的方法。您要等待某种条件,或者等待信号。当工作线程意识到将标志减为0时,使工作线程提高条件或信号。     

要回复问题请先登录注册