我有一个由 OpenMP 并行化的for循环。我希望并行线程用myGlobal = set()
generated_list = [(1,1), (21,22), (84,6)]
myGlobal = myGlobal.union(set(generated_list))
print(myGlobal)
generated_list = [(1,1), (21,22), (9,18), (71, 89), (13, 21)]
myGlobal = myGlobal.union(set(generated_list))
print(myGlobal)
填充{(21, 22), (1, 1), (84, 6)}
{(21, 22), (71, 89), (84, 6), (9, 18), (1, 1), (13, 21)}
的{{1}}。每个线程应写入其自己的向量条目。但是有时一项任务失败。这怎么会发生?
std::vector<bool>
向量可能最终看起来像这样:
falses
答案 0 :(得分:0)
问题是由于std::vector<bool>
的存储方式所致。它是为提高空间效率而设计的,并且将元素存储在单个位中,而不是字节中。这意味着vec[0]
,vec[1]
,... vec[7]
的分配都写入内存中的同一字节。由于您有多个线程写入同一个地址(实际上是一个读-修改-写序列),因此存在竞争条件。这可能导致一个线程的写操作被后续线程的写操作“撤消”。
此外,由于主内存的带宽限制,在这样的内存密集型循环中潜在的性能优势并不大。结合每个线程所需的缓存无效化,线程性能可能会低于单线程操作。
在这里完成了基本的基本操作(将内存设置为true)后,只需将其编码为标准的非OMP单线程循环即可。编译器将能够将其优化为合理的性能。
答案 1 :(得分:0)
根据标准,当同时修改同一容器中不同元素中包含的对象的内容时,需要所有标准容器来避免数据争用。
std::vector<bool>
除外。
1201ProgramAlarm解释了原因。
std::vector<bool>
在许多问题上都是臭名昭著的-最直接的解决方案是改用std::vector<char>
。如果这样做的话,您的程序就可以了,尽管您不应期望在这种特定情况下使用OpenMP可以提高性能。
答案 2 :(得分:-1)
我的openmp生锈了,但是想到的是#pragma omp flush [(list)]
openmp中的flush指令可用于标识同步点,该点定义为程序执行过程中执行线程需要具有一致的内存视图的点。一致的内存视图具有 2 要求:所有内存读/写操作之前和之后,必须在之前执行刷新指令或之后。这通常称为内存围栏。第163页,Chandra,Dagum,Kohr,Maydan,McDonald,Menon的openmp中的并行编程; 2001
书中对此进行了更详细的描述,并提到了在任何同步点上未保留在缓冲区/寄存器中的变量,根据您发布的代码,您并没有这样做。
几乎没有代码发布,并且我不知道如何或何时检查vec[i]
,所以这是我的第一个猜测...然后检查linux操作系统的版本,C编译器,并且涉及到openmp版本...
但是我不希望操作系统升级,编译器升级或openmp版本升级能够更正您遇到的代码
非常类似于在执行标准printf("hello")
时执行fflush(stdout)
而没有遵循printf("hello\n")
时执行标准\n
时发生的情况。 {{1}}导致在所有被认为是理所当然的系统上发生固有的刷新。