Concurrency 赛车状态示例
在硬件和软件方面,赛车条件的一些实际例子是什么? 这个例子不应该是关于解释什么是竞争条件的代码,而应该是系统中的一种情况Concurrency 赛车状态示例,concurrency,operating-system,cpu,race-condition,cpu-architecture,Concurrency,Operating System,Cpu,Race Condition,Cpu Architecture,在硬件和软件方面,赛车条件的一些实际例子是什么? 这个例子不应该是关于解释什么是竞争条件的代码,而应该是系统中的一种情况 例如,当两个音乐播放器试图访问扬声器时。您可以通过下面的一个简单示例进行很好的解释: 我将引用最重要的部分(老实说,这几乎是完整的文章) Visual Basic代码: 'Thread 1 Total = Total + val1 'Thread 2 Total = Total - val2 'Thread 1 1. mov e
例如,当两个音乐播放器试图访问扬声器时。您可以通过下面的一个简单示例进行很好的解释: 我将引用最重要的部分(老实说,这几乎是完整的文章) Visual Basic代码:
'Thread 1
Total = Total + val1
'Thread 2
Total = Total - val2
'Thread 1
1. mov eax,dword ptr ds:[031B49DCh]
2. add eax,edi
3. jno 00000033
4. xor ecx,ecx
5. call 7611097F
6. mov dword ptr ds:[031B49DCh],eax
'Thread 2
1. mov eax,dword ptr ds:[031B49DCh]
2. sub eax,edi
3. jno 00000033
4. xor ecx,ecx
5. call 76110BE7
6. mov dword ptr ds:[031B49DCh],eax
汇编代码(带行号)来自
前面的Visual Basic代码:
'Thread 1
Total = Total + val1
'Thread 2
Total = Total - val2
'Thread 1
1. mov eax,dword ptr ds:[031B49DCh]
2. add eax,edi
3. jno 00000033
4. xor ecx,ecx
5. call 7611097F
6. mov dword ptr ds:[031B49DCh],eax
'Thread 2
1. mov eax,dword ptr ds:[031B49DCh]
2. sub eax,edi
3. jno 00000033
4. xor ecx,ecx
5. call 76110BE7
6. mov dword ptr ds:[031B49DCh],eax
通过查看汇编代码,您可以看到
处理器在较低级别执行简单的
加法计算。一个线程可以执行全部或部分
它在处理器上运行期间的汇编代码。现在看看
此代码中出现竞态条件
总数是100,val1是50,val2是15。线程1得到了一个机会
执行,但仅完成步骤1至3。这意味着
线程1读取变量并完成加法。线程1现在被激活
只是等待写出它的新值150。在线程1之后
停止,线程2将完全执行。这意味着它已经
将计算出的值(85)写入变量总数。
最后,线程1恢复控制并完成执行。它写道
输出其值(150)。因此,当线程1完成时,值
现在,总数中有150人,而不是85人
编辑:如果我错了,请有人纠正我
我看到你编辑了你的问题,以明确你的疑问,因此我将相应地扩展我的答案。实际上,有两个音乐播放器试图访问扬声器以输出声音可能与有两个线程试图写入
stdout
没有多大区别。有一个公共缓冲区,数据被发送到该缓冲区,然后由(对于扬声器)驱动程序进行处理。stdout
示例的结果是,字符可以交错,在扬声器中也会发生同样的情况:声音将交错,因为不能同时播放这两种声音。因此,竞赛条件后果也适用于“系统情况”。关于您的编辑,我也编辑了我的答案。我希望它更有用。stdio
函数使用锁定,因此一个printf
中的字符不能与另一个线程中的fwrite
中的字符混合(或覆盖)。但是两个单独的printf
调用不能保证是连续的。相关:有更多关于原子增量与单独加载/增量/存储的信息。@Peter Cordes我不知道,我很感谢你的评论。我基于我的stdout示例,在这里你可以看到输出是交错的,但那是因为他们每次都在写一个字符(这是我在回答中想到的),原因是putc
很慢(而且用这种方式使用它会很愚蠢),因为它必须锁定/解锁stdio,否则,多个线程可能会在输出缓冲区中覆盖彼此的数据,甚至损坏数据结构。getc/putc_允许快速一次字符I/O,但当然不能同时从多个线程使用。无论如何,是的,在这个例子中,一个线程中的putc
与另一个线程中的putc
竞争,以便在每次一个线程释放锁时获取锁。可能在stdout未缓冲时,stdio代码中没有锁,它们最终只是直接进行write
系统调用。在这种情况下,线程在内核内相互竞争,以查看哪个write()。