首页 > 编程语言 > 详细

visual studio C++ 使用OpenMP 进行并行计算

时间:2020-09-19 20:52:01      阅读:81      评论:0      收藏:0      [点我收藏+]

section语句是用在sections语句里用来将sections语句里的代码划分成几个不同的段

#pragma omp [parallel] sections [子句]
{
   #pragma omp section
   {
            代码块
   } 
}
     当存在可选参数#pragma omp parallel sections时,块中的代码section才会并行处理,而#pragma omp  sections是串行的程序。详见下面的代码:
  1.  
    #include<stdio.h>
  2.  
    #include<stdlib.h>
  3.  
    #include<omp.h>
  4.  
    #include <unistd.h>
  5.  
    int main()
  6.  
    {
  7.  
     
  8.  
     
  9.  
    printf("parent threadid:%d\n",omp_get_thread_num());
  10.  
    #pragma omp sections
  11.  
    {
  12.  
    #pragma omp section
  13.  
    {
  14.  
    printf("section 0,threadid=%d\n",omp_get_thread_num());
  15.  
    sleep(1);
  16.  
    }
  17.  
    #pragma omp section
  18.  
    {
  19.  
    printf("section 1,threadid=%d\n",omp_get_thread_num());
  20.  
    //sleep(1);
  21.  
    }
  22.  
    #pragma omp section
  23.  
    {
  24.  
    printf("section 2,threadid=%d\n",omp_get_thread_num());
  25.  
    sleep(1);
  26.  
    }
  27.  
    }
  28.  
    #pragma omp parallel sections
  29.  
    {
  30.  
    #pragma omp section
  31.  
    {
  32.  
    printf("section 3,threadid=%d\n",omp_get_thread_num());
  33.  
    sleep(1);
  34.  
    }
  35.  
    #pragma omp section
  36.  
    {
  37.  
    printf("section 4,threadid=%d\n",omp_get_thread_num());
  38.  
    sleep(1);
  39.  
    }
  40.  
    #pragma omp section
  41.  
    {
  42.  
    printf("section 5,threadid=%d\n",omp_get_thread_num());
  43.  
    sleep(1);
  44.  
    }
  45.  
    }
  46.  
     
  47.  
    return 0;
  48.  
    }

输出结果为:

 

parent threadid:0
section 0,threadid=0
section 1,threadid=0
section 2,threadid=0
section 3,threadid=0
section 4,threadid=2
section 5,threadid=1

 

针对上面的代码,首先应该明确下面几点:

   1. sections之间是串行的。主线程把section0~2执行完之后才执行的第二个sections。

   2.没有加parallel的sections里面的section是串行的,为此我专门sleep了一秒,结果显示0~2都是主线程做的。

   3.第二个sections里面是并行的,进程编号分别为0,2,1。

问题来了,第二部分的0是不是主线程呢?还是第二部分新开的一个线程?为此需要真正输出每个线程在内核中的线程编号:

  1.  
    #include<stdio.h>
  2.  
    #include<stdlib.h>
  3.  
    #include<omp.h>
  4.  
    #include <unistd.h>
  5.  
    #include <sys/types.h>
  6.  
    #include <sys/syscall.h>
  7.  
     
  8.  
    int main()
  9.  
    {
  10.  
     
  11.  
    printf("pid:%d,tid=%ld\n",getpid(),syscall(SYS_gettid));
  12.  
    #pragma omp sections
  13.  
    {
  14.  
    #pragma omp section
  15.  
    {
  16.  
    printf("section 0,tid=%ld\n",syscall(SYS_gettid));
  17.  
    sleep(1);
  18.  
    }
  19.  
    #pragma omp section
  20.  
    {
  21.  
    printf("section 1,tid=%ld\n",syscall(SYS_gettid));
  22.  
    //sleep(1);
  23.  
    }
  24.  
    #pragma omp section
  25.  
    {
  26.  
    printf("section 2,tid=%ld\n",syscall(SYS_gettid));
  27.  
    sleep(1);
  28.  
    }
  29.  
    }
  30.  
    #pragma omp parallel sections
  31.  
    {
  32.  
    #pragma omp section
  33.  
    {
  34.  
    printf("section 3,tid=%ld\n",syscall(SYS_gettid));
  35.  
    sleep(1);
  36.  
    }
  37.  
    #pragma omp section
  38.  
    {
  39.  
    printf("section 4,tid=%ld\n",syscall(SYS_gettid));
  40.  
    sleep(1);
  41.  
    }
  42.  
    #pragma omp section
  43.  
    {
  44.  
    printf("section 5,tid=%ld\n",syscall(SYS_gettid));
  45.  
    sleep(1);
  46.  
    }
  47.  
    }
  48.  
     
  49.  
    return 0;
  50.  
    }

输出结果:

技术分享图片
pid:7619,tid=7619
section 0,tid=7619
section 1,tid=7619
section 2,tid=7619
section 5,tid=7621
section 4,tid=7619
section 3,tid=7620

从结果中可以看出以下几点:

  1. OpenMP上说当程序执行到第二个sections是并行的,主线程是休眠的,一直等所有的子线程都执行完毕之后才唤醒,可是在第二个sections中有个线程id和主线程id一致?其实是不一致的,首先从两者的类型上来看,线程编号是long int的,而进程是int的,数字一致并不能说两者相同。另外一方面,在linuxthreads时代,线程称为轻量级进程(LWP),也就是每个线程就是个进程,每个线程(进程)ID不同;而从2.4.10后,采用NPTL(Native Posix Thread Library)的线程库, 各个线程同样是通过fork实现的,并且具备同一个父进程。
  2. 主进程id为7619,同时它又有个线程id也是7619,又一次证明在linux中线程进程差别不大。
  3. 猜测主线程并不是休眠,而是将原先的上下文保存,然后自身也作为并行的一份子进行并行程序的执行,当并行程序完成之后,再回复原先的上下文信息。

下面是一个比较复杂的例子

  1.  
    #include<stdio.h>
  2.  
    #include<stdlib.h>
  3.  
    #include<omp.h>
  4.  
    #include <unistd.h>
  5.  
    #include <sys/types.h>
  6.  
    #include <sys/syscall.h>
  7.  
     
  8.  
    int main()
  9.  
    {
  10.  
    #pragma omp parallel
  11.  
    {
  12.  
    printf("pid:%d,tid=%ld\n",getpid(),syscall(SYS_gettid));
  13.  
    #pragma omp sections
  14.  
    {
  15.  
    #pragma omp section
  16.  
    {
  17.  
    printf("section 0,tid=%ld\n",syscall(SYS_gettid));
  18.  
    //sleep(1);
  19.  
    }
  20.  
    #pragma omp section
  21.  
    {
  22.  
    printf("section 1,tid=%ld\n",syscall(SYS_gettid));
  23.  
    sleep(1);
  24.  
    }
  25.  
    #pragma omp section
  26.  
    {
  27.  
    printf("section 2,tid=%ld\n",syscall(SYS_gettid));
  28.  
    sleep(1);
  29.  
    }
  30.  
    }
  31.  
    #pragma omp sections
  32.  
    {
  33.  
    #pragma omp section
  34.  
    {
  35.  
    printf("section 3,tid=%ld\n",syscall(SYS_gettid));
  36.  
    sleep(1);
  37.  
    }
  38.  
    #pragma omp section
  39.  
    {
  40.  
    printf("section 4,tid=%ld\n",syscall(SYS_gettid));
  41.  
    sleep(1);
  42.  
    }
  43.  
    #pragma omp section
  44.  
    {
  45.  
    printf("section 5,tid=%ld\n",syscall(SYS_gettid));
  46.  
    sleep(1);
  47.  
    }
  48.  
    }
  49.  
    }
  50.  
     
  51.  
    return 0;
  52.  
    }

 

输出结果:

技术分享图片
pid:7660,tid=7660
section 0,tid=7660
section 1,tid=7660
pid:7660,tid=7662
section 2,tid=7662
pid:7660,tid=7663
pid:7660,tid=7661
section 3,tid=7660
section 5,tid=7661
section 4,tid=7662
技术分享图片

#pragma omp parallel里面的代码是并行处理的,但是并不意味着代码要执行N次(其中N为核数),sections之间是串行的,而并行的实际部分是sections内部的代码。当线程7660在处理0,1时,因为section1休眠1s,所以section2在此期间会被新的线程进行处理。第一个sections真正处理完成之后,第二个sections才开始并行处理。

另外值得注意的是,printf并不是并行的函数,它是将结果输出到控制台中,可是控制台资源并不是共享的。当被某个线程占用之后,其余的线程只能等待,拿输出的结果为例。对于#pragma omp parallel里面的代码是并行的,可是线程之间还是有先后的次序的,次序和线程的创建时间有关,对于线程7660来说,本身就已经存在了,所以首先获得printf函数,而直到它执行section0里面的printf时,其他的线程还没有创建完毕,接着是setion1里面的printf,即使是这个时候有其他的线程创建完成了,也只能等待,在section1中,sleep了1秒钟,printf函数被新的线程使用,下面也如此。

visual studio C++ 使用OpenMP 进行并行计算

原文:https://www.cnblogs.com/profession/p/13697215.html

(0)
(0)
   
举报
评论 一句话评论(0
分享档案
最新文章
教程昨日排行
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!