Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C+中良性竞争条件的保证+; P>我知道C++标准在数据竞争的存在下不能保证任何东西(我相信数据竞赛有未定义的行为,意思是任何事情,包括程序终止,修改随机内存等等)。_C++_Multithreading_Race Condition - Fatal编程技术网

C+中良性竞争条件的保证+; P>我知道C++标准在数据竞争的存在下不能保证任何东西(我相信数据竞赛有未定义的行为,意思是任何事情,包括程序终止,修改随机内存等等)。

C+中良性竞争条件的保证+; P>我知道C++标准在数据竞争的存在下不能保证任何东西(我相信数据竞赛有未定义的行为,意思是任何事情,包括程序终止,修改随机内存等等)。,c++,multithreading,race-condition,C++,Multithreading,Race Condition,是否存在这样一种体系结构:一个线程写入内存位置,另一个线程从同一位置读取数据(不同步),这样的数据竞争不会导致读取操作读取未定义的值,并且内存位置“最终”(在内存屏障之后)处于这种状态是否更新为写入操作写入的值 < >用“数据竞赛”代替“种族条件”[< p> >你可以使用Linux操作系统,在那里你可以在C++进程中通过父进程分叉2个或多个子进程,你可以使两者同时访问一个内存位置,通过使用同步,你可以实现你想要做的事情。 ,'s_算法,,一个总是导致争用位置的示例:要求两个线程向相同的变量写入不

是否存在这样一种体系结构:一个线程写入内存位置,另一个线程从同一位置读取数据(不同步),这样的数据竞争不会导致读取操作读取未定义的值,并且内存位置“最终”(在内存屏障之后)处于这种状态是否更新为写入操作写入的值


< >用“数据竞赛”代替“种族条件”[

< p> >你可以使用Linux操作系统,在那里你可以在C++进程中通过父进程分叉2个或多个子进程,你可以使两者同时访问一个内存位置,通过使用同步,你可以实现你想要做的事情。
,'s_算法,,

一个总是导致争用位置的示例:要求两个线程向相同的变量写入不同的值。 让我们假设

  • 线程1将变量a设置为1
  • 线程将两组变量a设置为2
您将获得竞态条件,即使使用互斥锁,例如:

  • 如果先执行线程1,则得到a=1,然后是a=2
  • 如果先执行线程2,则得到a=2,然后是a=1
线程的顺序取决于操作系统,并且没有关于哪个线程将是第一个线程的保证。否则它将是连续的,不需要在单独的线程中执行

现在假设您根本没有同步,并且在第一个线程中执行a=a+1,在第二个线程中执行a=a+2。 a的初始值为0

在汇编程序中,生成的代码是将a的值复制到一个寄存器中,向其中添加1(对于第一个线程,则为2)

如果您根本没有同步,例如,您可以按以下顺序进行

  • Thread1:复制到reg1的值。reg1包含0

  • Thread2:复制到reg2的值。reg2包含0

  • Thread1:reg1的值已添加到1。现在包含1个

  • Thread2:reg2的值已添加到2。现在包含2个

  • Thread1:reg1的值已添加到1。现在包含1个

  • Thread2:reg2的值已添加到2。现在包含2个

  • Thread1:将reg1的值放入a。现在a包含1

  • Thread2:将reg2的值放入a。现在a包含2个

如果执行了thread1,则按顺序执行thread2,最后的a=3

现在假设a是一个指针(adressm),如您所知,获取错误的指针地址会导致程序崩溃。因此,错误的同步可能导致程序崩溃

有意义吗?

数据争用的问题不是,您可能在机器级别读取错误的值。数据竞争的问题是,编译器和处理器都对代码执行大量优化。为了确保这些优化在存在多个线程的情况下是正确的,它们需要关于可在线程之间共享的变量的附加信息。例如,此类优化可以:

  • 重新排序操作
  • 添加其他加载和存储操作
  • 删除加载和存储操作
汉斯·博姆(Hans Boehm)有一篇很好的论文叫《良性数据竞赛》。以下摘录摘自本文:

重复检查延迟初始化

众所周知,这在源代码中是不正确的 水平。一个典型的用例看起来像

if (!init_flag) {
    lock();
    if (!init_flag) {
        my_data = ...;
        init_flag = true;
    }
    unlock();
}
tmp = my_data;
没有任何东西可以阻止优化编译器重新排序
my_数据
init_标志
的加载,甚至从推进
my_数据的加载
在第一次测试
init_标志
之前,在条件if
init_标志
没有设定。某些非x86硬件可以执行类似的重新排序,即使编译器 不执行任何转换。这两种情况都可能导致最终读取
my\u数据
看到未初始化的值并产生不正确的结果


这里是另一个示例,
intx
是一个共享变量,
intr
是一个局部变量

int r = x;
if (r == 0)
    printf("foo\n");
if (r != 0)
    printf("bar\n");
如果我们只说,读取
x
会导致一个未定义的值,那么程序将打印“foo”或“bar”。但是,如果编译器按如下方式转换代码,程序也可能同时打印两个字符串或不打印任何字符串

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

如果您使用的是文件系统或内存映射文件,那么在同一进程中使用两个文件句柄(而不是一个)进行读写似乎可以减少争用条件。为什么您会在意呢?这样的程序会很糟糕,因为您永远无法将其安全地移植到另一个体系结构。别这样。使用std::mutex或原子。我之所以关心这个问题,是因为我计划在内存中映射文件的某个区域。有一个数据结构,指示文件的哪个部分被引用,哪个部分未被引用。我让一个线程上的读卡器读取文件的引用区域,另一个线程上的写卡器写入文件的未引用区域。我想了解如果文件损坏,并且写入程序在读卡器读取的区域中写入(我希望对可能发生的情况有最低限度的保证,例如没有崩溃,没有安全问题,…)会发生什么情况在双重检查示例中,编译器可以自由地重新排序。假设init_标志总是在数据竞争之后返回true,这难道不等于它吗?难道不是说程序的行为就好像读取操作读取了足够的未定义值一样吗?是的,这是有道理的。我的问题是,数据竞争是否会导致“a”之外的其他东西得到一个奇怪的值(它会导致程序termi吗