pthread vs openMP之我见

前两天看了些并行计算的文章,了解了一些并行计算的方法和原理。然后发现多线程实现里面还有个openMP,这个以前从来没见过(火星了),之前只是知道pthread线程库和微软也实现了一套线程。又看了看openMP的一些教程才知道它是怎么回事。

  pthread全称应该是POSIX THREAD,顾名思义这个肯定是按照POSIX对线程的标准而设计的。目前我所知道的有两个版本:Linux Thread(较早)和NPTL(主流?)。pthread库是一套关于线程的API,提供“遵循”(各平台实现各异)POSIX标准的线程相关的功能。

  openMP不同于pthread的地方是,它是根植于编译器的(也要包含头文件omp.h),而不是在各系统平台是做文章。它貌似更偏向于将原来串行化的程序,通过加入一些适当的编译器指令(compiler directive)变成并行执行,从而提高代码运行的速率。如:

 1 #include<omp.h>
 2 #include<stdio.h>
 3
 4  #define ARRAY_SIZE 1000
 5  #define CHUNK_SIZE 100
 6
 7  int main()
 8 {
 9     int array[ARRAY_SIZE];
10     int thread_num = ARRAY_SIZE/CHUNK_SIZE+1;
11     omp_set_num_threads(thread_num);
12
13     //init array
14      int i;
15     for(i=0;i<ARRAY_SIZE;i++)
16     {
17         array[i]=i;
18     }
19
20  #pragma omp parallel for schedule(guided,CHUNK_SIZE) private(i)
21     for(i=0;i<ARRAY_SIZE;i++)
22     {
23         int n = array[i];
24         int num_of_one=0;
25         if(n!=0)
26         {
27             num_of_one++;
28             while((n=n&(n-1))!=0)
29             {
30                 num_of_one++;
31             }
32         }
33         array[i]=num_of_one;
34
35     }
36     for(i=0;i<ARRAY_SIZE;i++)
37     {
38         printf("%d ",array[i]);
39     }
40     printf("\n");
41     return 0;
42
43 }
44
45  

  上面一段代码是通过加了一条函数调用(11行)和一条编译器指令(20行),从而将原来的循环分给多个线程来做。(本程序是计算0~ArraySize-1的每个数中二进制包含1个数)。

  而对于一开始就打算用并行方法来实现的程序,用pthread应该是更方便和更清晰。

下面是分别用pthread和openMP实现的worker_and_consumer:

pthread版:

代码

 1 #include<unistd.h>
 2 #include<pthread.h>
 3 #include<stdio.h>
 4 #include<stdlib.h>
 5
 6  #define SIZE 100
 7  #define THREAD_NUM_WORKER 15
 8 #define THREAD_NUM_CONSUMER 10
 9 #define SLEEP_WORKERS 2
10 #define SLEEP_CONSUMERS 1
11
12 int warehouse[SIZE];
13 int at =-1;
14 int is_end =0;
15 pthread_mutex_t space = PTHREAD_MUTEX_INITIALIZER;
16 pthread_mutex_t end   = PTHREAD_MUTEX_INITIALIZER;
17
18 void* consumer_func(void*);
19 void* worker_func(void*);
20
21 int main()
22 {
23     pthread_t workers[THREAD_NUM_WORKER];
24     pthread_t consumers[THREAD_NUM_CONSUMER];
25     int i,j;
26     int n;
27     for(i=0;i<THREAD_NUM_WORKER;i++)
28         pthread_create(&workers[i],NULL,worker_func,NULL);
29     for(j=0;j<THREAD_NUM_CONSUMER;j++)
30         pthread_create(&consumers[j],NULL,consumer_func,NULL);
31     while(is_end==0)
32     {
33         scanf("%d",&n);
34         if(n==0)
35         {
36             pthread_mutex_lock(&end);
37             is_end=1;
38             pthread_mutex_unlock(&end);
39         }
40     }
41     for(i=0;i<THREAD_NUM_WORKER;i++)
42             pthread_join(workers[i],NULL);
43     for(j=0;j<THREAD_NUM_CONSUMER;j++)
44             pthread_join(consumers[j],NULL);
45     return 0;
46 }
47
48 void* worker_func(void* var)
49 {
50     while(1)
51     {
52         if(is_end)
53             break;
54         //保护at变量
55         pthread_mutex_lock(&space);
56         if(SIZE-at-1>0)
57         {
58             printf("Make %d by worker %lld ",warehouse[++at]=rand(),pthread_self());
59             printf("and at is %d\n",at);
60         }
61         pthread_mutex_unlock(&space);
62         sleep(SLEEP_WORKERS);
63     }
64     return NULL;
65 }
66
67
68 void* consumer_func(void* var)
69 {
70     while(1)
71     {
72         if(is_end)
73             break;
74         pthread_mutex_lock(&space);
75         if(at>=0)
76         {
77             printf("Got %d by consumer %lld\n",warehouse[at--],pthread_self());
78             printf("and at is %d\n",at);
79         }
80         pthread_mutex_unlock(&space);
81         sleep(SLEEP_CONSUMERS);
82     }
83     return NULL;
84 }
85
86
87
88 

openMP版:

代码

 1 #include<unistd.h>
 2 #include<stdio.h>
 3 #include<stdlib.h>
 4 #include<omp.h>
 5
 6
 7 #define SIZE 100
 8 #define THREAD_NUM_WORKER 15
 9 #define THREAD_NUM_CONSUMER 10
10 #define SLEEP_WORKERS 2
11 #define SLEEP_CONSUMERS 1
12
13 int warehouse[SIZE];
14 int at =-1;
15 int is_end =0;
16
17 void start_workers()
18 {
19     omp_set_num_threads(THREAD_NUM_WORKER);
20 #pragma omp parallel default(shared)
21     {
22         if(omp_get_thread_num()==0)
23             printf("worker num is %d\n",omp_get_num_threads());
24         while(1)
25         {
26                 if(is_end)
27                     break;
28 //保护at变量
29 #pragma omp critical(space)
30             {
31                 if(SIZE-at-1>0)
32                 {
33                     printf("Make %d by worker %d ",warehouse[++at]=rand(),omp_get_thread_num());
34                     printf("and at is %d\n",at);
35                 }
36             }
37             sleep(SLEEP_WORKERS);
38         }
39     }
40 }
41
42
43 void start_consumers(void)
44 {
45     omp_set_num_threads(THREAD_NUM_CONSUMER);
46 #pragma omp parallel default(shared)
47     {
48         if(omp_get_thread_num()==0)
49             printf("consumer num is %d\n",omp_get_num_threads());
50         while(1)
51         {
52             if(is_end)
53                 break;
54 #pragma omp critical(space)
55             {
56                 if(at>=0)
57                 {
58                     printf("Got %d by consumer %d\n",warehouse[at--],omp_get_thread_num());
59                     printf("and at is %d\n",at);
60                 }
61             }
62             sleep(SLEEP_CONSUMERS);
63         }
64     }
65 }
66
67 int main()
68 {
69     omp_set_dynamic(0);
70     omp_set_nested(1);//这个不设置的话,就不能嵌套fork子线程咯
71     //先设置3个线程,每个线程完成一个section
72     omp_set_num_threads(3);
73 #pragma omp parallel sections
74     {
75 #pragma omp section
76         {
77             start_workers();
78         }
79 #pragma omp section
80         {
81             start_consumers();
82         }
83 #pragma omp section
84         {
85             int in;
86             scanf("%d",&in);
87             if(!in)
88             {
89 //保护is_end
90 #pragma omg critical(end)
91                 is_end =1;
92             }
93         }
94     }
95     return 0;
96 }
97
98
99 

  最后说一下,用openMP,编译时要加上选项-fopenmp,编译pthread时加上链接-lpthread。另外openMP有个缺点是若是代码中编译指令出错时,找错还是挺麻烦的,就像昨晚我把#pragma omp parallel写成了#pragma omg parallel,结果编译链接通过后却始终只有一个线程(主线程),找了好久...囧!

时间: 2024-09-20 00:49:22

pthread vs openMP之我见的相关文章

OpenMP #pragma omp parallel for并行化小探究

今天用了一下openmp,本人表示非常喜欢openmp的傻瓜化模式,导入一个头文件 直接parallel for #include <iostream> #include <omp.h> using namespace std; int main() { //cout<<"Thread num == "<<omp_get_thread_num()<<endl; #pragma omp parallel for num_thre

linux-c++,pthread合并ppm图片

问题描述 c++,pthread合并ppm图片 程序作用:1. 创建4个线程,读取4张PPM图片(都是350*350),合并生成一张PPM图片(700*700).2. 改写成 创建进程(fork),读取4张PPM图片(都是350*350),合并生成一张PPM图片(700*700).我写的代码如下,不知为何只能显示一张图片: #include <iostream>#include <fstream>#include <stdlib.h>#include <sys/w

Title与H1之我见 关系与区别浅析

title与H1之我见 各位站长在建站时,都会在网站或文章前应用大标题<H1>属性和title网站标题属性.很多新站长在网站SEO过程中,会认为把H1等同于Title.其实两是有区别和联系的,两者不能划等号.下面主要从文章和页面角度分析title和H1. H1等同于title吗? H1不等于title.H1,大标题.一般出现在文章页面,作用如同一张报纸的大标题,使用读者在没看内容之前就大概了解本文的旨意,它是直接给用户看的.在SEO中,搜索引擎也非常重视H1,目的是告诉搜索引擎,这个地方的内容

OpenMP 线程同步之临界区

多核/多线程编程中肯定会用到同步互斥操作.除了互斥变量以为,就是临界区. 临界区是指在用一时刻只允许一个线程执行的一段用{...},包围的代码段. 在OpenMP中临界区声明方法如下: #pragma omp critical [(name)] //[]表示名字可选 { //需要同一时刻只能有一个线程访问的代码 } 如下面的代码: #include <stdio.h> #include <omp.h> int main() { int sum = 0; #pragma omp pa

简述OpenMP中的线程任务调度

OpenMP中任务调度主要针对并行的for循环,当循环中每次迭代的计算量不相等时,如果简单地给各个线程分配相同次数的迭代,则可能会造成各个线程计算负载的不平衡,影响程序的整体性能. 如下面的代码中,如果每个线程执行的任务数量平均分配,有的线程会结束早,有的线程结束晚: #include<stdio.h> #include<omp.h> int main(){ int a[100][100] = {0}; #pragma omp parallel for for (int i =0;

OpenMP框架入门

OpenMP 框架是使用 C.C++ 和 Fortran 进行并发编程的一种强大方法.GNU Compiler Collection (GCC) V4.2 支持 OpenMP 2.5 标准,而 GCC 4.4 支持最新的 OpenMP 3 标准.包括 Microsoft? Visual Studio 在内的其他编译器也支持 OpenMP.在本文中,您可以学习使用 OpenMP 编译指示 (pragma),寻找对 OpenMP 提供的一些应用程序编程接口 (API) 的 支持,并使用一些并行算法对

基于pthread

以下是对pthread_create,readlink,getpid等函数的用法进行了详细的分析介绍,需要的朋友可以参考下   pthread_create是UNIX环境创建线程函数     具体格式:   #include<pthread.h>   int pthread_create(pthread_t *restrict tidp,const pthread_attr_t *restrict attr,void*(*start_rtn)(void*),void *restrict arg

《高级进阶DB2(第2版)——内部结构、高级管理与问题诊断》之我见

<高级进阶DB2(第2版)--内部结构.高级管理与问题诊断>之我见 从IT开发与运维角度来分析,千千万万的业务应用系统,最核心的最有价值的是业务数据:而这些多年来积累与沉淀下来的数据依托于数据库系统,数据库系统是否稳定与性能高低则是考验数据库内核,而作为核心之重的数据库内核则是各种商用与开源数据库服务器软件实现与关注的重点所在. 从数据库服务器软件的市场来看,DB2所占据的地位与份额真是犹如乒乓球界的王晧与羽毛球界的李宗伟,长期占居千年老二之位,位亦如其名啊(*_*) 作为要立志成为资深的DB

OpenMP基础----以图像处理中的问题为例

    OpenMP2.5规范中,对于可以多线程执行的循环有如下5点约束: 1.循环语句中的循环变量必须是有符号整形,如果是无符号整形就无法使用,OpenMP3.0中取消了这个约束 2.循环语句中的比较操作必须是这样的样式:loop_variable <,<=,>,>=loop_invariant_interger 3.循环语句中必须是整数加,整数减,加减的数值必须是循环不变量 4.如果比较操作是<,<=,那么循环变量的值在每次迭代时候必须增加,反之亦然 5.循环必须是