假设我们根据以下类型声明有几个数组
bool B[ N ];
Bar Foo[ M ];
int B_of_Foo[ M ]; // 0 <= B_of_Foo[m] < N
B
和Foo
可能包含任意值(取决于上下文),而B_of_Foo
包含的条目仅限于0
和N-1
之间的索引。我们来看看下面的代码
bool repeat = true
while( repeat ) {
repeat = false;
for( int m = 0; m < M; m++ ) {
if( complicated_condition( Foo[m] ) {
B [ B_of_Foo[ m ] ] = true
repeat |= true;
}
}
}
如果B的某些AND或OR为真但complicated_condition
为假,则 B[ B_of_Foo[ m ] ]
为真。保证在顺序执行时完成此代码。我想将其与OpenMP并行化。可以通过还原来处理可变重复。我想知道是否更新
B [ B_of_Foo[ m ] ] = true
然后必须将标记为原子操作。
我认为任何并发或重复的更新都会产生相同的结果。即使一个线程使用过时版本的B[ B_of_Foo[ m ] ]
检查complex_condition,其后续的写操作也不会改变B的那个条目,即使重复while循环而没有更新B,代码也是稳定的。
答案 0 :(得分:1)
是的,B [ B_of_Foo[ m ] ]
的更新需要是原子的(或以其他方式序列化),因为多个线程写入同一个变量的结果是未指定的,甚至如果他们正在编写相同的价值。来自OpenMP 3标准的1.4.1节(内存模型):
如果多个线程在没有同步的情况下写入同一个内存单元,包括由于如上所述的原子性考虑而导致的情况,则会发生数据争用。类似地,如果至少一个线程从存储器单元读取并且至少一个线程在没有同步的情况下写入同一存储器单元,包括由于如上所述的原子性考虑而导致的情况,则发生数据竞争。如果发生数据争用,则未指定程序的结果。
在开始时,大多数人都会想到一种内存模型,其中存在某种类型的顺序一致性保证 - 比如在POSIX文件系统中 - 如果发生两个并发写操作,它们的行为就好像它们是随机序列化一样“中奖”。在教授数据竞赛时,大多数使用的例子都没有用。但是没有这样的东西得到保证,原则上结果可能是完全的胡言乱语。 (无论是在 practice 中发生在你最喜欢的架构上是一个不同的问题。在这里,你的值是单个字节,我不得不认为你在x86的大多数实现中都没问题。但是没有任何保证。)