简体   繁体   English

保证C ++中的良性竞争条件

[英]Guarantees of benign race conditions in C++

I know the C++ standard doesn't guarantee anything in presence of a data race (I believe a data race has undefined behavior, meaning anything goes, including program termination, modifying random memory, etc...). 我知道C ++标准并不保证存在数据竞争的任何东西(我相信数据竞争具有未定义的行为,意味着任何事情都会发生,包括程序终止,修改随机内存等等)。

Is there any architecture where a data race that consists of one thread writing to a memory location and one thread reading from the same location (without synchronization) doesnt result in the read operation reading an undefined value and where the memory location is "ultimately" (after a memory barrier) updated to the value that was written by the write operation? 是否有任何架构,其中包含一个线程写入内存位置的数据争用和一个从同一位置读取的线程(没有同步)不会导致读取操作读取未定义的值以及内存位置“最终”(在内存屏障之后)更新为写操作写入的值?

[edited to replace "race condition" with "data race"] [编辑以“数据竞赛”取代“竞争条件”]

The problem with data races is not, that you can read a wrong value on a machine level. 数据争用的问题不在于,您可以在计算机级别读取错误的值。 The problem with data races is, that both compiler and processor perform a lot of optimizations on the code. 数据竞争的问题在于,编译器和处理器都对代码执行了大量优化。 To make sure that these optimizations are correct in the presence of multiple threads, they need additional information about variables that can be shared between threads. 为了确保在存在多个线程时这些优化是正确的,它们需要有关可在线程之间共享的变量的其他信息。 Such optimizations can for example: 这样的优化可以例如:

  • reorder operations 重新排序操作
  • add additional load and store operations 添加额外的加载和存储操作
  • remove load and store operations 删除加载和存储操作

There is a good paper benign data races by Hans Boehm called How to miscompile programs with "benign" data races . 汉斯·博姆(Hans Boehm)有一篇很好的纸质良性数据竞赛,名为“ 如何用”良性“数据竞赛错误编写程序 The following excerpt is taken from this paper: 以下摘录摘自本文:

Double checks for lazy initialization 双重检查延迟初始化

This is well-known to be incorrect at the source-code level. 众所周知,这在源代码级别是不正确的。 A typical use case looks something like 典型的用例看起来像

 if (!init_flag) { lock(); if (!init_flag) { my_data = ...; init_flag = true; } unlock(); } tmp = my_data; 

Nothing prevents an optimizing compiler from either reordering the setting of my_data with that of init_flag , or even from advancing the load of my_data to before the first test of init_flag , reloading it in the conditional if init_flag was not set. 没有什么能够阻止优化编译器从任一重排序的设定my_data的与init_flag ,或甚至的负载前进my_data的第一测试前init_flag ,在有条件的重装,如果init_flag没有设置。 Some non-x86 hardware can perform similar reorderings even if the compiler performs no transformation. 即使编译器不执行转换,某些非x86硬件也可以执行类似的重新排序。 Either of these can result in the final read of my_data seeing an uninitialized value and producing incorrect results. 这些中的任何一个都可能导致my_data的最终读取看到未初始化的值并产生不正确的结果。


Here is another example, where int x is a shared and int r is a local variable. 这是另一个例子,其中int x是共享的, int r是局部变量。

int r = x;
if (r == 0)
    printf("foo\n");
if (r != 0)
    printf("bar\n");

If we would only say, that reading x leads to an undefined value, then the program would either print "foo" or "bar". 如果我们只说,读取x导致未定义的值,那么程序将打印“foo”或“bar”。 But if the compiler transform the code as follows, the program might also print both strings or none of them. 但是如果编译器按如下方式转换代码,程序也可能会打印两个字符串或者不打印任何字符串。

if (x == 0)
    printf("foo\n");
if (x != 0)
    printf("bar\n");

you can use linux OS where you can fork a 2 or more child process over a parent process in c++,you can make both to access one memory location and , by using synchronization you can achieve what you wanna do.--> How to share memory between process fork()? 您可以使用Linux操作系统,您可以在c ++中通过父进程分叉2个或更多子进程,您可以同时访问一个内存位置,通过使用同步,您可以实现您想要的目标.--> 如何共享进程fork()之间的内存? , http://en.wikipedia.org/wiki/Dekker 's_algorithm , http://en.wikipedia.org/wiki/Readers%E2%80%93writers_problem , http ://en.wikipedia.org/wiki/Dekker's_algorithm,http: //en.wikipedia.org/wiki/Readers%E2%80%93writers_problem ,

One example that will always result in a race location: ask two threads to write a different value to the same variable. 一个总是会导致竞争位置的示例:要求两个线程将不同的值写入同一个变量。 Let's assume that 让我们假设一下

  • thread one sets variable a to 1 线程一将变量a设置为1
  • thread two sets variable a to 2 线程二将变量a设置为2

You will get race condition , even with a mutex for example because 你会得到竞争条件 ,即使是使用互斥锁,例如因为

  • if thread one is executed first then you get a=1 then a=2. 如果首先执行线程1,则得到a = 1,然后a = 2。
  • if thread two is executed first then you get a=2 then a=1. 如果首先执行线程2,则得到a = 2,然后a = 1。

The order of the threads is depending on the os and there is not guratantee about which thread will be first. 线程的顺序取决于操作系统,并且没有关于首先使用哪个线程的保证。 Otherwise it would be sequential and no need to do it in separate threads. 否则它将是顺序的,不需要在单独的线程中执行它。

Assume now that you have not synchronisation at all and you are doing a=a+1 in the first thread a=a+2 in the second thread. 现在假设您根本没有同步,并且您在第二个线程中的第一个线程a = a + 2中执行a = a + 1。 The inital value of a is 0. a的初始值为0。

In assembly the code being generated is copy the value of a into one register, add 1 to it (in the case of the first thread, 2 otherwise). 在汇编中,生成的代码是将a的值复制到一个寄存器中,向它添加1(在第一个线程的情况下,否则为2)。

If you have no synchronization at all you can have the following order for example 如果您根本没有同步,则可以使用以下顺序

  • Thread1: value of a copied to reg1. Thread1:复制到reg1的值。 reg1 contains 0 reg1包含0

  • Thread2: value of a copied to reg2. Thread2:复制到reg2的值。 reg2 contains 0 reg2包含0

  • Thread1: value of reg1 added 1. Now contains 1 Thread1:reg1的值加1.现在包含1

  • Thread2: value of reg2 added 2. Now contains 2 Thread2:添加了reg2的值2.现在包含2

  • Thread1: value of reg1 added 1. Now contains 1 Thread1:reg1的值加1.现在包含1

  • Thread2: value of reg2 added 2. Now contains 2 Thread2:添加了reg2的值2.现在包含2

  • Thread1: value of reg1 put to a. Thread1:reg1的值放到a。 Now a contains 1 现在一个包含1

  • Thread2: value of reg2 put to a. Thread2:reg2的值放到a。 Now a contains 2 现在一个包含2

If you have thread1 executed then sequentially thread 2 you would have a=3 at the end. 如果你执行了thread1然后顺序线程2,你最后会有一个= 3。

Now imagine a is a pointer, ie an adressm so as you know, getting a wrong pointer adress can cause the program to crash. 现在假设a是一个指针,即一个adressm,因为你知道,得到一个错误的指针地址会导致程序崩溃。 So a wrong synchronization can cause the program to crash . 因此错误的同步会导致程序崩溃

Makes sense? 说得通?

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

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