在多线程编程中必须考虑到不同的线程对同一个变量进行读写访问引起的数据竞争问题。如果线程间没有互斥机制,则不同线程对同一变量的访问顺序是不确定的,有可能导致错误的执行结果。

OpenMP中有两种不同类型的线程同步机制,一种是互斥机制,一种是事件同步机制。


互斥锁机制的设计思路是对一块共享的存储空间进行保护,保证任何时候最多只能有一个线程对这块存储空间进行访问,从而保证数据的完整性,这块存储空间称为“临界区”。可以通过critical、atomic等制导指令以及API中的互斥函数来实现。

事件同步机制的设计思路是控制线程的执行顺序,可以通过设置barrier同步路障、ordered定序区段、matser主线程执行等实现。

互斥锁之critical定义临界区

使用critical定义临界区的格式如下:

#pragma omp critical {需要被保护的代码块}

例如如下示例:

#include<iostream>
#include"omp.h" using namespace std; void main()
{
int sum = 0;
#pragma omp parallel for for (int i = 0; i < 10000; i++)
{
#pragma omp critical
{
sum += i;
}
}
cout << sum << endl;
system("pause");
}

加上critical之后可以保证每次执行结果总是正确的,值为49995000,但如果不加critical语句,结果可能不确定,某次执行的结果为:46932347。

互斥锁之atomic原子操作

制导指令critical可以定义一个任意大小的代码块作为临界区保护,atomic原子操作应用在单条赋值语句中。

#include<iostream>
#include"omp.h" using namespace std; void main()
{
int sum = 0;
#pragma omp parallel for for (int i = 0; i < 10000; i++)
{
{
#pragma omp atomic
sum += i;
}
}
cout << sum << endl;
system("pause");
}

事件同步之barrier(同步路障)

barrier是OpenMP中线程同步的一种方法,在多线程代码块中插入barrier,则先完成计算任务的线程到达此处会等待,直到最后一个线程也完成了计算任务。barrier相当于设置了一个线程的集合点,所有线程都到达之后才能继续往下执行。

#include<iostream>
#include"omp.h" using namespace std; int sum = 0; void Initialization()
{
for (int i = 0; i < 5; i++)
{
sum += i;
}
} void main()
{
#pragma omp parallel
{
Initialization();
#pragma omp barrier
printf("i=%d, thread_id=%d\n", sum, omp_get_thread_num());
}
system("pause");
}

输出:

如果没有添加barrier,由于不同的线程可能同时访问sum变量,存在数据竞争问题,导致输出的sum结果值不确定,其中一次输出为:

事件同步之ordered顺序制导

在循环代码中某些代码的执行需要按规定的顺序执行,比如在一个循环中,一部分的工作可以并行执行,而特定的部分需要按照串行的工作流程依次执行。

#include<iostream>
#include"omp.h" using namespace std; void main()
{
#pragma omp parallel for ordered
for (int i = 0; i < 5; i++)
{
#pragma omp ordered
printf("i=%d, thread_id=%d\n", i, omp_get_thread_num());
}
system("pause");
}

输出:

输出是按照i从小到达的次序依次执行的,如果不加ordered,其中一次输出为:

事件同步之master主线程执行

master制导指令用于指定一个代码块是交由主线程执行,这个代码块虽然位于parallel的并行域中,但是并不会被多个线程执行。

#include<iostream>
#include"omp.h" using namespace std; void main()
{
#pragma omp parallel
{
#pragma omp master
for (int i = 0; i<5; i++)
{
printf("i=%d, thread_id=%d\n", i, omp_get_thread_num());
}
} system("pause");
}

输出:

只有线程0,即主线程执行了该语句,如果不加master指令,其中一次输出为:

最新文章

  1. Mybatis XML配置
  2. Xamarin Android 所见即所得问题
  3. PAT 02-线性结构2 一元多项式的乘法与加法运算 (20分)
  4. 小白linux安装php 5.6+nginx配置(踩坑版)
  5. poj 1698 Alice‘s Chance
  6. Particle Playground 3.03 - 粒子特效王者
  7. bnuoj 44359 快来买肉松饼
  8. [UVa1213]Sum of Different Primes(递推,01背包)
  9. ti processor sdk linux am335x evm /bin/setup-package-install.sh hacking
  10. 游戏开发设计模式之原型模式 &amp; unity3d JSON的使用(unity3d 示例实现)
  11. rsyslog Properties 属性:
  12. Application.DoEvents()
  13. javascript日历插件
  14. java从命令行接收多个数字,求和程序分析
  15. Linux系统管理命令(1)accton的使用
  16. Python中如何防止sql注入
  17. codeforces 893A Chess For Three 模拟
  18. yii2.0中添加二维数组,多条数据。
  19. RobotFramework下的http接口自动化Create Http Context关键字的使用
  20. Windows10最新更新破坏了PowerShell功能

热门文章

  1. SDUT OJ 2862 勾股定理
  2. 《编程导论(Java)&amp;#183;4.1数据抽象的含义》
  3. bc-win32-power-echo-vim-not-work
  4. Vue源码--解读vue响应式原理
  5. ios开发网络学习四:NSURLConnection大文件断点下载
  6. Android自定义组件系列【3】——自定义ViewGroup实现侧滑
  7. 【t040】SETI任务
  8. java十五个常用类学习及方法举例
  9. UIPasteboard粘贴板:UIlabel开启复制粘贴功能(一)
  10. 【BZOJ 1036】[ZJOI2008]树的统计Count