简体   繁体   English

C ++是从不同的线程编写和读取变量的未定义行为

[英]C++ Is writing and reading a variable from different threads undefined behavior

Since I've started multi-threading, I've been asking myself this one question : 自从我开始多线程以来,我一直在问自己这个问题:

Is writing and reading a variable from different threads undefined behavior? 是从不同的线程编写和读取变量未定义的行为?

Let's use the minimal example where we increment an integer in a thread and read the integer inside another one. 让我们使用最小的例子,我们在一个线程中递增一个整数并读取另一个中的整数。

void thread1()
{
    x++;
}

void thread2()
{
    if (x == 5)
    {
        //doSomething
    }
}

I understand that the addition operation is not atomic and therefore I could make a read from the second thread while the first thread is in the middle of the adding operation, but there is something i'm not quite sure of. 我理解添加操作不是原子的,因此我可以在第一个线程处于添加操作的中间时从第二个线程读取,但是有些东西我不太确定。

Does x keeps his value until the whole addition operation is completed and then is assigned this new value, or does x have an intermediate state where reading from it would result in undefined behavior. x是否保持其值直到整个加法操作完成然后被赋予此新值,或者x是否具有中间状态,其中从中读取将导致未定义的行为。

If the first theory applies, then reading from x while it's being writing to would simply return the value before the addition and wouldn't be so problematic. 如果第一个理论适用,那么在写入时从x读取只会在添加之前返回值,并且不会出现问题。

If the second theory is true, could someone explain more in detail what is the process of the addition operation and why it would be undefined behavior (maybe with an example?) 如果第二个理论是正确的,那么有人可以更详细地解释添加操作的过程是什么以及为什么它将是未定义的行为(可能有一个例子?)

Thanks 谢谢

The comments already got the basics right. 评论已经得到了正确的基础知识。

The compiler, when compiling a single function may consider the ways in which a variable is changed. 编译单个函数时,编译器可以考虑变量的更改方式。 If the function cannot directly or indirectly change a certain variable, then the compiler may assume that there is no change to that variable whatsoever, unless there's thread synchronization. 如果函数不能直接或间接地改变某个变量,那么编译器可以假设该变量没有任何变化, 除非有线程同步。 In that case the compiler must deal with the possibility of another thread changing those variables. 在这种情况下,编译器必须处理另一个线程更改这些变量的可能性。

If the compiler assumption is violated (ie you have a bug), then literally anything may happen. 如果违反了编译器假设(即你有一个bug),那么任何事情都可能发生。 This is not constrained, because that would severely restrict optimizers. 这不受限制,因为这会严重限制优化器。 You may make some assumptions that x has some unique address in memory, but optimizers are known to move variables around and have multiple variables share a single address (just at different times). 你可以假设x在内存中有一些唯一的地址,但是已知优化器可以移动变量并让多个变量共享一个地址(只是在不同的时间)。 Such optimizations may very well be justified based on a single-thread assumption, one that your example is violating. 基于单线程假设,这种优化很可能是合理的,这是您的示例违反的假设。 Your second thread may think it's looking at x , but it might also be getting y . 你的第二个线程可能会认为它正在看x ,但也可能会得到y

x (32bit variable) will be always defined on 32+bits cpu however not so precisely. x(32位变量)将始终在32 +位cpu上定义,但不是那么精确。 You know that x can be any value from start up to end range defined by ++. 您知道x可以是++定义的从开始到结束范围的任何值。

like in following case: x is initialized to 0 and you call 5 times thread1 the thread 2 can see this x in range from 0 to 5. 类似于下面的情况:x被初始化为0并且你调用5次thread1,线程2可以看到这个x在0到5的范围内。

It means I can consider assignment of integer to memory as atomic. 这意味着我可以考虑将整数分配给内存作为原子。

There are some reasons why x on both thread is not synchronized eg while x on thread1 is 5 on the thread2 can be 0 in the same time. 有两个原因导致两个线程上的x不同步,例如,当thread1上的x为5时,thread2上的x可以同时为0。 One of the reason is cpu cache which is different for each core. 其中一个原因是cpu cache对于每个核心都是不同的。 To synchronise the value between caches you have to use memory barriers. 要同步缓存之间的值,您必须使用内存屏障。 You can use for example std::atomic which do a great job for you 你可以使用例如std :: atomic ,它可以为你做得很好

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM