2012-11-14 36 views
2

如果我有多个线程试图将相同的值写入内存中的单个位置,是否有可能产生竞争条件?在写入过程中,数据会不知何故被破坏?没有先前的读取或测试条件,只有写...是否有可能存在只写操作的争用条件?

编辑:澄清,我正在GPU上计算点产品。我使用多个线程来计算单个产品(每行/列元素一个线程)并将它们保存到内存中的临时位置。然后我需要总结这些中间产品并保存结果。

我在考虑让所有线程分别执行此总和/存储操作,因为在GPU上分支可能会损害性能。 (你会认为它应该花费相同的时间来处理sum/store,无论它是由单个线程还是所有线程完成的,但是我已经测试过了,性能下降很小。)所有线程都会得到相同的总和,但是当他们每个人都试图将他们的答案写入记忆中的同一位置时,我就担心竞争状况。在我所做的有限测试中,一切看起来都很好,但我仍然很紧张......

+0

为什么您的线程将** **值写入位置? –

+3

这个问题没有一般的答案。有一个C++ 11的答案,有一个Windows线程答案,还有一个POSIX pthreads答案,等等。另外,“只写操作”是什么意思?你的意思是一种以高级语言写入的操作,如“i = 1;”?或者你的意思是汇编语言指令?或者是其他东西?因为这也给出了不同的答案。 –

+0

你是否想要订购?你正试图解决什么样的用例? – Scorpion

回答

2

多线程在CUDA中编写单个(推测共享或全局)内存位置,即使是“同时”,即来自同一行代码也没有问题。

如果您关心写入的顺序,那么这是一个问题,因为CUDA无法保证顺序,因为多个线程对相同的内存位置执行相同的写入操作。如果这是一个问题,你应该使用原子或其他重构你的代码的方法来整理它。 (这听起来不像这是你的问题。)

大概,正如另一个响应者所说,你关心的结果在一些点。因此,有必要设置某种屏障,无论是明确的(例如,对于使用共享内存的块内的多个线程,__synchthreads())或隐式(例如内核结束,用于多线程写入全局内存中的位置),然后再读取该位置,并期望获得明智的结果。请注意,这些并不是唯一可能给您带来理智结果的障碍方法,只有两个例子。翘曲同步行为或其他聪明的编码技术可以用来确保读取完成后的读取完整性。

+0

写入的顺序应该不重要,因为所有线程都写入相同的值。在写入之后,我总是有一个'__syncthreads()'调用,所以我认为后续的读取应该没问题。 – tpm1510

1

如果只写操作不是原子显然会有另一个线程可能会观察到损坏中的数据州。

例如写入64位整数,即存储为一对32位整数。

线程A - 刚写完高位字,线程B刚刚写完低位字,并且要设置高位字;

线程C可以看到,整数包括由线程B和线程A

P.S.写入高阶字写入一个低位字的这个问题非常普遍,实际结果将取决于环境(语言)的内存模型和底层处理器体系结构(硬件)。

4

在大多数平台的大多数线程标准下,这只是被禁止或未定义的。也就是说,你不能这样做,如果你这样做,任何事情都可能发生。

像C和C++的高级语言编译器可以根据假设你不会做任何你不允许做的事情来优化代码。因此,“只写”操作可能不是这样的事情。如果使用C或C++编写i = 1;,则编译器可以自由生成与编写i = 0; i++;时相同的代码。同样混杂的优化确实发生在现实世界中。

相反,请遵循适用于使用适当的同步基元的任何线程模型的规则。如果您的平台提供它们,请使用适当的原子操作。

2

虽然表面上答案似乎是否定的,没有竞争条件,但答案有点微妙。 Boris在某些32位体系结构中正确地说,存储64位长或地址可能需要两次操作,因此可能会在无效状态下读取。这可能很难重现,因为内存页面通常会被更新,并且很长一段时间永远不会跨越内存页面。

但是,更重要的问题是,您需要认识到,如果没有内存同步,当线程将看到更新的值时,不会有任何保证围绕。线程可能会长时间运行,从内存中读取过时的值。这不会是一个无效值,但它不会是最近写的。这可能不会特别引起“竞争条件”,但它可能会导致程序以意想不到的方式执行。

此外,虽然你说它是“只写”,但显然有人正在读取值,否则将没有理由执行更新。代码的哪个部分读取值的详细信息会更好地告诉我们,只写入没有同步是否真的安全。

+0

是的,最终我确实读了价值。我在求和步骤之后立即同步线程,所以读取应该没问题。 – tpm1510

+0

糟糕,我的意思是在_write_之后立即发生同步,这跟随总和。 – tpm1510

相关问题