数据相关及解决
串行程序改为并行程序,最容易出现的新问题,就是数据相关与冲突了。本来由一个线程做的工作,分给多个线程做,自然会出现一些千丝万缕的瓜葛,如同一个人做的项目,现在由几个人来做,难免需要额外沟通和解释的。
数据相关的解决技术在OpenMP也已经比较完善了。结合OS的思想,数据冲突主要利用临界区和信号量来解决,另外OpenMP增加了数据规约。下面我们分别谈谈各自使用方法。
临界区
万不得已的选择,因为它是并行程序中不得不串行的区域集合。所以,我们追求“小”,一个临界区可以拆分的话,尽量拆分。临界区的工作原理,是需要排队,然后依次执行的,所以效率很低。
具体语句为:#pragma omp critical
例子:累加求和。对于和的结果sum变量是共享的,所以需要临界区保护,但是效率已经降低为串行。
数据规约
由于临界区的效率比较低,不能实现真正意义上的并行,而对于某些问题是可以通过分解的思路进行并行的。比如,上面的累加求和,是可以通过分别累加,然后再汇总的思路完成的,于是出现了数据规约的思想。
语法:#pragma omp for reduction(+:sum)
上述语句就是将sum变量在每个线程中生成一个副本,计算各自线程中累加的结果,然后最后累加到共享的sum变量中。效率明显提高了吧?不过,这种用法是有局限性的,大家可以体会到写法上涉及到操作,所以,该用法只能用于基本运算符中的操作,譬如加减乘除之类的。
原子操作
微型临界区。大家可能都听说过原子性,原子操作就是为了将读写绑定到一起,从而避免与更新有关的冲突,由于该“串行工作量”非常小,所以说原子操作提供了一种更高效率的互斥锁机制。
#pragma omp atomic
同样,原子操作也是只能用于特定的原子运算符:+,-,*,/,|,&,^,<<,>>.
注意:以上语句一般都是在parallel语句内部使用,因为主要是由并发引出的一系列数据冲突问题,所以要在并行代码内解决这些冲突~