这是一个竞争条件?(Is this a race condition?)

2019-07-31 01:40发布

的争用条件的定义:争用条件或种族危险是在一个系统或过程,由此该过程的输出或结果是出乎意料和严重依赖于其他事件的顺序或定时的缺陷。

请看下面的伪代码:

    Global variable i initialized to 6;
    Thread 1: 
        acquire(lock l)
        increment global variable i, i.e. i++;

    Thread 2: 
       acquire(lock l)
       double the value of global var i, i.e.: i*=2;

如果T1获取锁升第一和第二T2 i的值将是14。另一方面,如果T2首先获取锁升和T1第二i的值将是13。

所以,这是一个竞争条件或没有?

更新:一些意见和答案后,意见仍然分歧。 我的意见是在“没错,这是一个竞争条件”的范畴。 其实我给这个例子作为竞争条件的情况下,在不同的问题。 与此同时,我还可以在“NO,这不是一个竞争条件”类阅读一些有趣的评论。 我想我会解决,并得出结论,这是或不是取决于视角/水平从一个着眼于问题的竞争条件。 不过,我仍然在等待答案有趣/评论。

Answer 1:

我认为,例如算法是否具有竞争条件依赖于什么样的算法是意料中的事。

有上的修改没有数据争i -这些访问被串行化并且相对于彼此发生原子。

但是,如果是到增量乘法(反之亦然)之前发生算法的正确性很重要,再有就是比赛等手段将不得不使用该算法的执行进行同步。 如果算法被认为是计算复杂的方式i * 2 + 1 (荒谬,因为它可能是执行使用线程的计算),然后有一个争用条件。

考虑下面的程序片段:

int data;

pthread_cond_t condvar = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mux = PTHREAD_MUTEX_INITIALIZER;

void* wait_for_data(void*)
{
    pthread_mutex_lock( &mux);
    pthread_cond_wait( &condvar, &mux);

    puts("got the data: %d\n", data);

    pthread_mutex_unlock( &mux);

    return 0;
}


void* set_data(void*)
{
    pthread_mutex_lock( &mux);

    data = 42;

    pthread_cond_signal( &condvar);

    pthread_mutex_unlock( &mux);

    return 0;
}

这两个线程都基本上完全相互排斥的 - 没有数据的比赛。 但是,如果set_data()信号之前,条件变量wait_for_data()都绕在其上等待, wait_for_data()将永远不会完成。 我想大多数人会说这就是一个竞争状态,由于使用不当的条件变量。



Answer 2:

不,这不对。 因为它读取和写入我之前锁定。 因此,读取和您的示例将始终保持一致。 当然,应该在每次操作后解锁,但我猜你只是忘了补充一点,在你的伪代码。



Answer 3:

不,这是执行的预期序列之一。 种族是没有保护计数器带有某种锁定的,因此允许加载修改店内周期同时运行。

编辑0:

@Gheorghe,想想两个人走自己的钱出来的差异在银行办公室在同一时间联合银行账户的例子和。 在每个位置业务员需要检查账户余额,给了现金,并记下新的平衡。 如果即帐户未在此操作过程中“锁定”,这不是“原子”关于平衡,他们可能最终得到与他们两个那么他们在银行有更多的钱。 银行不喜欢这样。

但是,如果帐户同时被操纵锁定,并输出取决于时机? 是的,绝对 - 总和没有改变,但他们两个人之间的分离可以是不同的。

重要的是保护价值的一致性 - 不管以什么顺序和多少次,这两个家伙拿钱从后面,他们没有得到更多然后他们原本。



Answer 4:

注:我给出一个答案从Java透视图的问题源于有关Java的内存模型前面的讨论 。

似乎有很多混乱围绕“竞态条件”,这就是为什么你得到不同的答案的定义。

如果你的意思是“数据竞争”,只有一个在Java中的情况下有效的定义,它是由给定的Java语言规范17.4.5 :

当一个程序包含两个相互冲突的访问(§17.4.1)未下令由之前发生关系,据说含有数据的比赛。

冲突的访问被限定在17.4.1 :

两次访问(的读或写操作)相同的变量被说成是相互矛盾的,如果接入的至少一个是写入。

在你的情况,你的代码包含了之前发生所界定的关系17.4.5 :

在监视器上的解锁之前发生在该显示器上每一个后续的锁。

所以在你的代码中没有数据的比赛在Java方面-任何人说,否则使用非Java定义。

其他人评论了关于在任意2码的可以先运行意义上的“一般的比赛”,但是这是一个算法的问题:要么你的代码是并行的,它不应该的问题,或者它是不是和你应该按顺序运行它。 但是,这是一个错误,而不是一个数据的比赛。



Answer 5:

是。 顾名思义它是。 你也将有变波动性的问题。 在这种情况下,没有哪个线程从加载到寄存器内存变量的保证,然后将其保存到内存中。 因此,它可能是在某些情况下,一个线程会得到一个不完整的数值。 在许多语言中,你将不得不以某种方式确保你总是会取一个干净的副本。 (在Java中挥发性的)

http://www.freebsd.org/doc/en/books/developers-handbook/secure-race-conditions.html

我认为这是一个很好的定义也。

阅读: http://dl.acm.org/citation.cfm?id=130623

“两个不同的概念已被隐含地认为是:一个关于旨在是确定性的(我们称之为一般比赛),另一种含有临界区(我们称之为数据争用)非确定性程序的程序。”

所以我想说,这是一个“普通比赛”,如果您认为程序总是产生相同的结果。 如果没有,你只是有很奇怪的设计。



文章来源: Is this a race condition?