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

时间:2014-03-30 16:41:54

标签: c++ multithreading race-condition

我知道C ++标准并不保证数据竞争存在的任何事情(我相信数据竞争有未定义的行为,意味着任何事情,包括程序终止,修改随机内存等......)。 / p>

是否有任何架构,其中包含一个写入内存位置的线程和一个从同一位置读取的线程(没有同步)的数据争用不会导致读取操作读取未定义的值,并且内存位置为& #34;最终" (在内存屏障之后)更新为写操作写入的值?

[编辑以取代"竞争条件"与"数据竞赛"]

3 个答案:

答案 0 :(得分:3)

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

  • 重新排序操作
  • 添加额外的加载和存储操作
  • 删除加载和存储操作

Hans Boehm有一篇名为How to miscompile programs with "benign" data races的好文章良性数据竞赛。以下摘录摘自本文:

  

仔细检查延迟初始化

     

众所周知,这在源代码中是不正确的   水平。典型的用例类似于

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

没有什么能阻止优化编译器重新排序设置   my_datainit_flag的{​​{1}},或甚至提升my_data的负载   在init_flag的第一次测试之前,在条件init_flag中重新加载它   没设定。即使编译器,某些非x86硬件也可以执行类似的重新排序   不执行任何转换。其中任何一个都可能导致my_data的最终读取   看到未初始化的值并产生不正确的结果。


以下是另一个示例,其中int x是共享的,int r是局部变量。

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");

答案 1 :(得分:0)

你可以使用Linux操作系统,你可以在c ++中通过父进程分叉2个或更多的子进程,你可以使两个访问一个内存位置,通过使用同步,你可以实现你想做的.--&gt ; How to share memory between process fork()?http://en.wikipedia.org/wiki/Dekker's_algorithm,http://en.wikipedia.org/wiki/Readers%E2%80%93writers_problem

答案 2 :(得分:0)

总是会产生竞赛位置的一个示例:要求两个线程为相同的变量写入不同的值。 我们假设

  • 线程一将变量a设置为1
  • 线程二将变量a设置为2

即使使用互斥锁,您也会获得竞争条件,因为

  • 如果先执行第一个线程,则得到a = 1,然后a = 2.
  • 如果先执行第二个线程,则得到a = 2,然后a = 1.

线程的顺序取决于操作系统,并且没有关于首先使用哪个线程的保证。否则它将是顺序的,不需要在单独的线程中进行。

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

在汇编中,生成的代码是将a的值复制到一个寄存器中,向它添加1(在第一个线程的情况下,否则为2)。

如果完全没有同步,您可以按照以下顺序进行操作

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

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

  • 线程1:增加了reg1的值1.现在包含1

  • 线程2:添加了reg2的值2.现在包含2

  • 线程1:增加了reg1的值1.现在包含1

  • 线程2:添加了reg2的值2.现在包含2

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

  • Thread2:reg2的值放到a。现在包含2

如果你执行了thread1然后顺序线程2,你最后会得到= 3.

现在假设a是一个指针,即一个地址,如你所知,得到一个错误的指针地址会导致程序崩溃。因此,错误的同步会导致程序崩溃

有道理吗?