【OpenMP】并行的中断,解决error C3010: “break”: 不允许跳出 OpenMP 结构化块

来源:互联网 发布:windows无法与dns通信 编辑:程序博客网 时间:2024/06/05 11:05

虽然我在《【OpenMP】Helloworld》(点击打开链接)与《【OpenMP】互斥》(点击打开链接)都提到过,OpenMP可以与多线程同样理解,但同时也提到过,两者的本质是不同的。最明显的区别,OpenMP是预分配任务的,每个CPU核算多少东西要事先平分,而多线程则在分时片之间存在竞争。最能说明的例子是,如果你的OpenMP出现如下的程序段:

#pragma omp parallel for num_threads(4)for(int i=0;i<200;i++){break;}

或者:

#pragma omp parallel num_threads(THREAD_NUM)while(中断条件){break;}

是不能通过编译的,系统会报:error C3010: “break”: 不允许跳出 OpenMP 结构化块。

这是因为,OpenMP在计算之前,会将实现分配CPU,例如如下代码:

#include "iostream"#include "omp.h"using namespace std;int main(){#pragma omp parallel for num_threads(4)for(int i=0;i<200;i++){}return 0;}

for的200次迭代会被分成连续的4段,扔给我这台电脑的4个CPU,0-49次迭代由0号CPU计算,50-99次迭代由1号CPU计算……以此类推。这个分配是在这个for被cpu计算前就执行的。

然而存在这样的情况:假设,我们希望这个i计算到第一个能被100整除且非0的数,也就是当i等于100的时候,就停止这个循环,i不要计算下去了。我最后希望得出i=100这个结果,同时用到OpenMP的cpu多核计算。我要用break;去停止,但上面提到过OpenMP的原理决定你无法用break,那该怎么办了。

当然,有人可能问为何,不直接让i自增到100得了,这只是举个例子,很多时候,你并不知道要并行多少次,比如,有个并行任务,就是并行一次将处理列表被处理的元素抹去,直到处理列表没有数位置,我又不知道处理列表到底有多长的时候……

于是,有人就开始疑惑我写成while行不行?为何网上说parallel的用法多以#pragma omp parallel for来举例,能否将在一个while{}前面加上#pragma omp parallel,然后将while的判断条件,改成我要跳出循环的条件。这是不对的,因为这样意思是创建若干个线程,每个线程都将执行后面的while语句,但是while循环并不会在各个线程之间进行分配。也就是说这个while语句会被多个线程重复执行。

那么,修改for循环,改成如下形式可以不?

#include "iostream"#include "omp.h"using namespace std;int main(){#pragma omp parallel for num_threads(4)for(int i=0;i<200&&(i!=0&&i%100==0);i++){}return 0;}
这也是不行了,因为上面已经提到过OpenMP中的#pragma omp parallel for,是严格分配CPU的,接下一行的for循环是有严格的格式限制的,这样写会引发:error C3017: OpenMP“for”语句中的终止测试格式不正确。


这是不是,如果涉及并行的中断,就不能用OpenMP呢?不是的,我们可以换种思维:既然OpenMP的并行不能中断,当计算已经满足条件的时候,让OpenMP的并行计算,空转就行了,不让break,又没有不能用continue。continue就是不执行这次循环的意思,较少使用但并不生僻的关键字。

上述程序可以写成如下:

#include "iostream"#include "omp.h"using namespace std;int main(){int result;//这里设置result来接受i被中断的时候的值int i=0;bool finish_flag=false;#pragma omp parallel for num_threads(4)for(i=0;i<200;i++){//计算之后无论得到这个i自增到什么值,都不会赋予给int i。int i的值,在#pragma omp parallel for num_threads(4)之后,还是保持不变。if(finish_flag==true){continue;}if(finish_flag==false){if(i!=0&&i%100==0){result=i;finish_flag=true;}}}cout<<result;return 0;}

或者这样:

#include "iostream"#include "omp.h"using namespace std;int main(){int result;bool finish_flag=false;#pragma omp parallel for num_threads(4)for(int i=0;i<200;i++){if(finish_flag==true){continue;}if(finish_flag==false){if(i!=0&&i%100==0){result=i;finish_flag=true;}}}cout<<result;return 0;}

亦或用while的形式,但while的形式需要用到OpenMP的临界区,不然最后算出来的结果是103。for则不需要。

#include "iostream"#include "omp.h"using namespace std;int main(){int i=0;bool finish_flag=false;#pragma omp parallel num_threads(4)while(!finish_flag){if(finish_flag==true){continue;}#pragma omp critical  {  if(finish_flag==false){if(i!=0&&i%100==0){finish_flag=true;}else{i++;}}}}cout<<i;return 0;}

感觉while的形式更能够让人理解,不过上述的程序无论写成怎么样,运行结果都是100:




0 0
原创粉丝点击