OpenMP 是一种共享内存范例。如果您可以保证所有不同的进程都会将相同的值写入相同的位置,那么让它们这样做就可以了。有竞态条件,但不会影响结果。
这给了你这个代码:
int* bitmap = ...; // pointer to bitmap data with width and height
#pragma omp parallel for collapse(2)
for(long iy=0; iy<height; iy++)
for(long ix=0; ix<width; ix++)
if(write_pattern(ix,iy))
apply_pattern(ix,iy, 0); // writes "0" to bitmap, write only, no read
如果你不能做出这样的保证,你可以使用临界区来限制写访问:
int* bitmap = ...; // pointer to bitmap data with width and height
#pragma omp parallel for collapse(2)
for(long iy=0; iy<height; iy++)
for(long ix=0; ix<width; ix++)
if(write_pattern(ix,iy)) {
#pragma omp critical
apply_pattern(ix,iy, 0); // writes "0" to bitmap, write only, no read
}
但是,如果您不能做出这样的保证,那么这是一个糟糕的并行候选方案,因为每次运行代码时,不同的进程将在不同的时间到达位图的不同部分。也就是说,执行顺序是不确定的,因此您将无法预测结果。假设只有一个正确的结果,您的流程必须产生相同的输出。
同样,请确保您使用apply_pattern() 更改原始数据以外的其他内容,否则您的结果将再次不确定,因为一个线程可能会在另一个线程看到修改部分之前或之后修改输入。
另一种策略是收集所有需要修改的地方,然后再依次编写它们。如果你的支票很贵但你的写作很便宜,这可能是有道理的;比如说,如果您使用正则表达式进行检查并写出零。
int* bitmap = ...; // pointer to bitmap data with width and height
typedef std::pair<long,long> gridloc;
std::vector<gridloc> patterns;
//Use a custom reduction operator, available in newer versions of OpenMP
#pragma omp declare reduction (merge : std::vector<gridloc> : omp_out.insert(omp_out.end(), omp_in.begin(), omp_in.end()))
#pragma omp parallel for collapse(2) reduction(merge:patterns)
for(long iy=0; iy<height; iy++)
for(long ix=0; ix<width; ix++)
if(write_pattern(ix,iy)) {
patterns.emplace_back(ix,iy)
}
for(const auto &c: patterns)
apply_pattern(c.first,c.second, 0); // writes "0" to bitmap, write only, no read
如果写入成本很高,您可以对patterns 的内容进行一些处理,以组合写入、消除冗余写入、对写入进行拓扑排序等。