C 这足以检测比赛情况吗?
假设我有一个多线程应用程序,我使用相同的输入运行它。它是否足以检测每个加载和存储以检测写入和写入读取数据竞争?我的意思是,从记录的加载和存储地址来看,如果我们可以看到哪个线程加载了哪个线程,哪个线程存储了哪个线程,那么我们可以通过注意重叠的地址来检测写读写数据竞争。还是我遗漏了什么 还是我遗漏了什么 你错过了很多。正如普比所说,如果你看到读,然后在T1中写,然后读,然后在T2中写,你就不能说没有种族了。你需要知道有关锁的情况 你可能想使用一个工具,比如谷歌的 更新: 但我的方法会覆盖所有比赛还是至少部分比赛 你在这里和其他答案上的评论似乎表明你不明白什么是种族 你的方法可能会暴露一些种族,是的。它保证不会覆盖其中的大部分(这将使练习徒劳无益) 还是我遗漏了什么 你错过了很多。正如普比所说,如果你看到读,然后在T1中写,然后读,然后在T2中写,你就不能说没有种族了。你需要知道有关锁的情况 你可能想使用一个工具,比如谷歌的 更新: 但我的方法会覆盖所有比赛还是至少部分比赛 你在这里和其他答案上的评论似乎表明你不明白什么是种族C 这足以检测比赛情况吗?,c,linux,gcc,C,Linux,Gcc,假设我有一个多线程应用程序,我使用相同的输入运行它。它是否足以检测每个加载和存储以检测写入和写入读取数据竞争?我的意思是,从记录的加载和存储地址来看,如果我们可以看到哪个线程加载了哪个线程,哪个线程存储了哪个线程,那么我们可以通过注意重叠的地址来检测写读写数据竞争。还是我遗漏了什么 还是我遗漏了什么 你错过了很多。正如普比所说,如果你看到读,然后在T1中写,然后读,然后在T2中写,你就不能说没有种族了。你需要知道有关锁的情况 你可能想使用一个工具,比如谷歌的 更新: 但我的方法会覆盖所有比赛还是
你的方法可能会暴露一些种族,是的。它保证不会覆盖大多数线程(这将使练习无效)。您将学到的最明显的一点是,有多个线程使用相同的内存。这本身并不一定不好 良好的用途包括信号量保护、原子访问和RCU或双缓冲等机制 不良使用包括种族条件、真实和错误共享:
- 竞争条件主要源于排序问题——如果某个任务a在其执行结束时写入某些内容,而任务B在其开始时需要该值,则最好确保B的读取仅在a完成后发生。信号量、信号或类似的东西是一个很好的解决方案。当然,也可以在同一个线程中运行它
- 真正的共享意味着两个或多个内核正在积极地读写相同的内存地址。这会降低处理器的速度,因为它将不断地向其他内核(当然还有内存)的缓存发送任何更改。您的方法可以抓住这一点,但可能不会突出它
- 假共享甚至比真共享更复杂:处理器缓存不在单个字节上工作,而是在“缓存线”上工作——缓存线包含多个值。如果core A继续敲打一行的字节0,而core B继续写入字节4,则缓存更新仍将使整个处理器暂停
- 竞争条件主要源于排序问题——如果某个任务a在其执行结束时写入某些内容,而任务B在其开始时需要该值,则最好确保B的读取仅在a完成后发生。信号量、信号或类似的东西是一个很好的解决方案。当然,也可以在同一个线程中运行它
- 真正的共享意味着两个或多个内核正在积极地读写相同的内存地址。这会降低处理器的速度,因为它将不断地向其他内核(当然还有内存)的缓存发送任何更改。您的方法可以抓住这一点,但可能不会突出它
- 假共享甚至比真共享更复杂:处理器缓存不在单个字节上工作,而是在“缓存线”上工作——缓存线包含多个值。如果core A继续敲打一行的字节0,而core B继续写入字节4,则缓存更新仍将使整个处理器暂停
- 整数i=0;(内存)
- T1将i的值从内存读入寄存器1:0
- T1增加寄存器1中i的值:(寄存器1内容)+1=1
- T1将寄存器1的值存储在内存中:1
- T2将i的值从内存读入寄存器2:1
- T2乘以寄存器2中i的值:(寄存器2内容)*2=2
- T2将寄存器2的值存储在内存中:2
- 整数i=2;(内存) 在上面所示的情况下,i的最终值是2,正如预期的那样。 但是,如果两个线程同时运行而未锁定或 同步时,操作的结果可能是错误的。这个 下面的备选操作顺序演示了此场景:
- 整数i=0;(内存)
- T1将i的值从内存读入寄存器1:0
- T2将i的值从内存读入寄存器2:0
- T1增加寄存器1中i的值:(寄存器1内容)+1=1
- T2乘以寄存器2中i的值:(寄存器2内容)*2=0
- T1将寄存器1的值存储在内存中:1
- T2将寄存器2的值存储在内存中:0
- 整数i=0;(内存) i的最终值为0,而不是预期的结果2。这 由于增量op
- 您将了解到的最明显的事情是,有多个线程使用相同的内存。这本身并不一定不好
良好的用途包括信号量保护、原子访问和RCU或双缓冲等机制
不良使用包括种族条件、真实和错误共享:
- 以下是一个来自维基百科的简单示例,我对其稍加修改:
作为一个简单的例子,让我们假设两个线程T1和T2各自需要
对一个全局整数的值执行算术运算。理想情况下
将进行以下操作顺序: