项目背景:

为了提升项目的运行效率,考虑多线程技术。最近OpenMP技术很热,咱也凑凑热闹,也为了充分发挥电脑硬件的能力。

硬件:

酷睿2双核 2.2GHz

3G 内存

软件:

Visual Studio 2010 旗舰版

Windows 7 旗舰版 32bit

难点:

由于多个线程操作同一个文件,很有可能存在线程冲突。

OpenMP:

1. 必须的头文件 <omp.h>

2. #pragma omp 预处理指示符指定要采用OpenMP。 例如通过 #pragma om parallel for 来指定下方的for循环采用多线程执行,此时编译器会根据CPU的个数来创建线程数。对于双核系统,编译器会默认创建两个线程执行并行区域的代码。

示例代码:

view plaincopy to clipboardprint?
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150

  1. #include <iostream>
  2. #include <stdio.h>
  3. #include <omp.h> // OpenMP编译需要包含的头文件
  4. int main()
  5. {
  6. #pragma omp parallel for
  7. for (int i = 0; i < 100; ++i)
  8. {
  9. std::cout << i << std::endl;
  10. }
  11. return 0;
  12. }

#include <iostream> #include <stdio.h> #include <omp.h> // OpenMP编译需要包含的头文件 int main() { #pragma omp parallel for for (int i = 0; i < 100; ++i) { std::cout << i << std::endl; } return 0; }

3. OpenMP 常用库函数

函数原型                                         功能

int omp_get_num_procs(void)      返回当前可用的处理器个数

int omp_get_num_threads(void)  返回当前并行区域中活动线程的个数,如果在并行区域外部调用,返回1

int omp_get_thread_num(void)    返回当前的线程号(omp_get_thread_ID更好一些)

int omp_set_num_threads(void)   设置进入并行区域时,将要创建的线程个数

3.1 并行区域

view plaincopy to clipboardprint?
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150

  1. #pragma omp parallel  //大括号内为并行区域
  2. {
  3. //put parallel code here.
  4. }

#pragma omp parallel //大括号内为并行区域 { //put parallel code here. }

3.2 库函数示例

view plaincopy to clipboardprint?
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150

  1. #include <iostream>
  2. #include <omp.h>
  3. int main()
  4. {
  5. std::cout << "Processors Number: " << omp_get_num_procs() << std::endl;
  6. std::cout << "Parallel area 1" << std::endl;
  7. #pragma omp parallel
  8. {
  9. std::cout << "Threads number: " << omp_get_num_threads() << std::endl;
  10. std::cout << "; this thread ID is " << omp_get_thread_num() << std::endl;
  11. }
  12. std::cout << "Parallel area 2" << std::endl;
  13. #pragma omp parallel
  14. {
  15. std::cout << "Number of threads: " << omp_get_num_threads() << std::endl;
  16. std::cout << "; this thread ID is " << omp_get_thread_num() << std::endl;
  17. }
  18. return 0;
  19. }

#include <iostream> #include <omp.h> int main() { std::cout << "Processors Number: " << omp_get_num_procs() << std::endl; std::cout << "Parallel area 1" << std::endl; #pragma omp parallel { std::cout << "Threads number: " << omp_get_num_threads() << std::endl; std::cout << "; this thread ID is " << omp_get_thread_num() << std::endl; } std::cout << "Parallel area 2" << std::endl; #pragma omp parallel { std::cout << "Number of threads: " << omp_get_num_threads() << std::endl; std::cout << "; this thread ID is " << omp_get_thread_num() << std::endl; } return 0; }

3.3 for循环并行化的基本用法

3.3.1 数据不相关性

利用openmp实现for循环的并行化,需满足数据的不相关性。

在循环并行化时,多个线程同时执行循环,迭代的顺序是不确定的。如果数据是非相关的,那么可以采用基本的 #pragma omp parallel for 预处理指示符。

如果语句S2与语句S1相关,那么必然存在以下两种情况之一:

1. 语句S1在一次迭代中访问存储单元L,而S2在随后的一次迭代中访问同一存储单元,称之为循环迭代相关(loop carried dependence);

2. S1和S2在同一循环迭代中访问同一存储单元L,但S1的执行在S2之前,称之为非循环迭代相关(loop-independent dependence)。

3.3.2 for循环并行化的几种声明形式

view plaincopy to clipboardprint?
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150

  1. #include <iostream>
  2. #include <omp.h>
  3. int main()
  4. {
  5. //声明形式一
  6. #pragma omp parallel
  7. {
  8. #pragma omp for
  9. for (int i = 0; i < 10; ++i)
  10. {
  11. std::cout << i << std::endl;
  12. }
  13. }
  14. //声明形式二
  15. #pragma omp parallel for
  16. for (int i = 0; i < 10; ++i)
  17. {
  18. std::cout << i << std:: endl;
  19. }
  20. return 0;
  21. }

#include <iostream> #include <omp.h> int main() { //声明形式一 #pragma omp parallel { #pragma omp for for (int i = 0; i < 10; ++i) { std::cout << i << std::endl; } } //声明形式二 #pragma omp parallel for for (int i = 0; i < 10; ++i) { std::cout << i << std:: endl; } return 0; }

上面代码的两种声明形式是一样的,可见第二种形式更为简洁。不过,第一种形式有一个好处:可以在并行区域内、for循环以外插入其他并行代码。

view plaincopy to clipboardprint?
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150

  1. //声明形式一
  2. #pragma omp parallel
  3. {
  4. std::cout << "OK." << std::endl;
  5. #pragma omp for
  6. for(int i = 0; i < 10; ++i)
  7. {
  8. std::cout << i << std::endl;
  9. }
  10. }
  11. //声明形式二
  12. #pragma omp parallel for
  13. //std::cout << "OK." << std::endl;      // error!
  14. for(int i = 0; i < 10; ++i)
  15. {
  16. std::cout << i << std::endl;
  17. }

//声明形式一 #pragma omp parallel { std::cout << "OK." << std::endl; #pragma omp for for(int i = 0; i < 10; ++i) { std::cout << i << std::endl; } } //声明形式二 #pragma omp parallel for //std::cout << "OK." << std::endl; // error! for(int i = 0; i < 10; ++i) { std::cout << i << std::endl; }

3.3.3 for 循环并行化的约束条件

尽管OpenMP可以很方便地对for循环进行并行化,但并不是所有的for循环都可以并行化。下面几种情形的for循环便不可以:

1. for循环的循环变量必须是有符号型。例如,for(unsigned int i = 0; i < 10; ++i){...}编译不通过。

2. for循环的比较操作符必须是<, <=, >, >=。例如,for(int i = 0; i != 10; i++)编译不通过。

3. for循环的增量必须是整数的加减,而且必须是一个循环不变量。例如,for(int i = 0; i < 10; i = i+1)编译不通过,感觉只能++i, i++, --i, i--。

4. for循环的比较操作符如果是<, <=,那么循环变量只能增加。例如,for(int i = 0; i != 10; --i)编译不通过。

5. 循环必须是单入口,单出口。循环内部不允许能够达到循环以外的跳出语句,exit除外。异常的处理也不必须在循环体内部处理。例如,如循环体内的break或者goto语句,会导致编译不通过。

3.3.4 基本for循环并行化示例

view plaincopy to clipboardprint?
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150

  1. #include <iostream>
  2. #include <omp.h>
  3. int main()
  4. {
  5. int a[10] = {1};
  6. int b[10] = {2};
  7. int c[10] = {3};
  8. #pragma omp parallel
  9. {
  10. #pragma omp for
  11. for(int i = 0; i < 10; ++i)
  12. {
  13. //c[i]只与a[i]和b[i]相关
  14. c[i] = a[i] + b[i];
  15. }
  16. }
  17. return 0;
  18. }

#include <iostream> #include <omp.h> int main() { int a[10] = {1}; int b[10] = {2}; int c[10] = {3}; #pragma omp parallel { #pragma omp for for(int i = 0; i < 10; ++i) { //c[i]只与a[i]和b[i]相关 c[i] = a[i] + b[i]; } } return 0; }

3.3.5 嵌套for循环

view plaincopy to clipboardprint?
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150

  1. #include <iostream>
  2. #include <omp.h>
  3. int main()
  4. {
  5. #pragma omp parallel
  6. {
  7. #pragma omp for
  8. for(int i = 0; i < 10; ++i)
  9. {
  10. for(int j = 0; j < 10; ++j)
  11. {
  12. c[i][j] = a[i][j] + b[i][j];
  13. }
  14. }
  15. }
  16. return 0;
  17. }

#include <iostream> #include <omp.h> int main() { #pragma omp parallel { #pragma omp for for(int i = 0; i < 10; ++i) { for(int j = 0; j < 10; ++j) { c[i][j] = a[i][j] + b[i][j]; } } } return 0; }

编译器会让第一个CPU完成

view plaincopy to clipboardprint?
  1. for(int i = 0; i < 5; ++i)
  2. {
  3. for(int j = 0; j < 5; ++j)
  4. {
  5. c[i][j] = a[i][j] + b[i][j];
  6. }
  7. }

for(int i = 0; i < 5; ++i) { for(int j = 0; j < 5; ++j) { c[i][j] = a[i][j] + b[i][j]; } }

让第二个CPU完成

view plaincopy to clipboardprint?
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150

  1. for(int i = 5; i < 10; ++i)
  2. {
  3. for(int j = 5; j < 10; ++j)
  4. {
  5. c[i][j] = a[i][j] + b[i][j];
  6. }
  7. }

for(int i = 5; i < 10; ++i) { for(int j = 5; j < 10; ++j) { c[i][j] = a[i][j] + b[i][j]; } }

转载于:https://www.cnblogs.com/BIGFOOT/archive/2011/09/01/2161621.html

OpenMP模式下多线程文件操作 (转)相关推荐

  1. 内核模式下的文件操作

    1.文件的创建 对文件的创建或者打开都是通过内核函数ZwCreateFile实现的.和Windows API类似,这个内核函数返回一个文件句柄,文件的所有操作都是依靠这个句柄进行操作的.在文件操作完毕 ...

  2. Linux下对文件操作时出现乱码怎么办?

    Linux下对文件操作经常会遇见乱码问题,我在网上搜了一些解决方法,希望能对大家有所帮助. 如果你需要在Linux中操作windows下的文件,那么你可能会经常遇到文件编码转换的问题.Windows中 ...

  3. SpringBoot打开resources目录下的文件操作

    SpringBoot打开resources目录下的文件操作 背景 我想在SpringBoot项目中放入一个静态文件.json文件.然后在SpringBoot项目内可以打开并读取此json文件. [外链 ...

  4. linux下怎么批量命名文件,linux下的文件操作——批量重命名

    概述:在日常工作中,我们经常需要对一批文件进行重命名操作,例如将所有的jpg文件改成bnp,将名字中的1改成one,等等.文本主要为你讲解如何实现这些操作 1.删除所有的 .bak 后缀: renam ...

  5. Linux中vim的三种命令格式,及命令模式下常见的操作

    目录 什么是vim 三种命令模式,以及相互转换 命令模式下的文本操作 什么是vim Vim是一个类似于Vi的著名的功能强大.高度可定制的文本编辑器,在Vi的基础上改进和增加了很多特性 三种命令模式,以 ...

  6. c++ windows获得当前工作目录文件_基于linux下Python文件操作

    Python中的文件操作 1.文件的打开与关闭 想一想:如果想用word编写一份简历,应该有哪些流程呢? 1.打开word软件,新建一个word文件 2.写入个人简历信息 3.保存文件 4.关闭wor ...

  7. bios x86保护模式下的软盘操作floppy

    Cpu启动时,如果在bios中设置了从软盘启动,则bios会自动把软盘的第一个扇区(512字节)搬移到0x7c00,然后会从0x7c00开始运行,我们需要在这512字节的程序中实现把boot从软盘中搬 ...

  8. linux 文件操作函数,Linux下的文件操作函数及creat用法

    编写Linux应用程序要用到如下工具: (1)编译器:GCC GCC是Linux平台下最重要的开发工具,它是GNU的C和C++编译器,其基本用法为:gcc [options] [filenames]. ...

  9. C# WPF Application 下的文件操作

    好气哦,电脑好烂,每天花大把的时间在等电脑反应上. 没有钱买新电脑,连组台式机的钱都没有.好气哦. 啊啊啊啊文件操作是什么鬼???C++下我都懵了,C#下好多东西要学!!!我不会!我不会!我不会!!! ...

最新文章

  1. 如何学习linux设备驱动
  2. 虚拟内存越大越好吗_手机的运行内存真的是越大越好吗?6GB和8GB到底又该如何选择?...
  3. HDU各种比赛题题解(一)
  4. Java 编程题自动评分技术的研究与实现(一)
  5. 手机秒变门禁卡,支持加密卡
  6. 组合数性质--二项式系数之和等于2^n的证明
  7. Array和Slices
  8. APM直升机调试记录
  9. OpenFace人脸分类器训练
  10. JWS 批注参考WebService注解
  11. 在h5页面中调起支付宝小程序中的某一个页面以及URLScheme 之 支付宝
  12. 盛迈坤电商:店铺详情页设置的特点
  13. Java——继承——Extends
  14. C语言中的静态变量和静态函数
  15. go : gin + lumberjack 输出日志文件
  16. 2.使用Gateway实现token校验
  17. 未来5年最有“钱景”的行业!两会上指明了~
  18. 明星“真空”出镜上直播,这戏该如何继续演?
  19. 手机浏览器APP哪几个值得推荐?为什么?
  20. geohash网格图_geoHash的数学局限

热门文章

  1. Java 11:字符串类中的新方法
  2. gradle maven_Gradle vs Maven
  3. partition拼字符串_Python字符串partition(),rpartition()
  4. python字符串_Python字符串
  5. ios控制ios_iOS UIMenuController UIMenuItem
  6. [已解决]Hibernate程序未终止
  7. Android版式– LinearLayout,RelativeLayout
  8. css base64 图片背景
  9. CloudStack 4.3功能前瞻
  10. 路由转发采用递归查询