高性能计算的线程模型:Pthreads 仍是 OpenMP

http://software.intel.com/zh-cn/articles/threading-models-for-high-performance-computing-pthreads-or-openmp

做者:Andrew Binstock
html


简介

UNIX 操做系统多年来一直支持线程,这是 UNIX 在服务器系统上异常活跃的主要缘由之一。在过去几年间,Linux* 一直宣传本身经过改进线程的内核支持而在服务器上的出色表现。例如,kernel 最近发布的 2.6 版增长了全新的调度程序,可以经过能够在 Linux 系统上切换的线程来大幅度优化速度。kernel 以前的版本(2.4 版--Linux kernel 使用偶数表明发布的版本,奇数表明正在开发的版本)一样根据线程能力的大幅度改进来划分。这些进步有助于将 Linux 放在服务器上和放入支持高性能计算(HPC)的站点中。此外,Linux 放弃其原有的线程 API(称为 Linux 线程)并采用 Pthreads 做为其固有的线程界面,链接目前可用的大部分 UNIX 变量。

然而,Linux 开发人员(如使用 UNIX 和 Windows* 的程序员)可使用称为 OpenMP* 的第二种线程 API,这由服务器厂商联盟精心设计而成。本文将 Pthreads 和 OpenMP 进行比较,并尝试肯定哪种可以使开发人员受益最多。 linux


Pthreads 是什么?

Pthreads 是 IEEE(电子和电气工程师协会)委员会开发的一组线程接口,负责指定便携式操做系统接口(POSIX)。Pthreads 中的 P 表示 POSIX,实际上,Pthreads 有时候也表明 POSIX 线程。基本上,POSIX 委员会定义了一系列基本功能和数据结构,它但愿可以被大量厂商采用,所以线程代码可以轻松地在操做系统上移植。委员会的梦想由 UNIX 厂商实现了,他们都大规模实施 Pthreads。(最著名的例外就是 Sun,它继续采用 Solaris* 线程做为其主要线程 API。)因为 Linux 的采用和移植到 Windows 平台,Pthreads 的可能性一直被进一步扩展。

Pthreads 指定 API 来处理线程要求的大部分行为。这些行为包括建立和终止线程、等待线程完成、以及管理线程之间的交互。后面的目录中存在各类锁定机制,可以阻止两个线程同时尝试修改相同的数据值:互斥体、条件变量和信号量。(从技术上讲,信号量不是 Pthreads 的一部分,可是它们从概念上更接近于与线程合做,并且可用于 Pthreads 可以运行的全部系统上。)

为了使用 Pthreads,开发人员必须为这一 API 专门编写代码。这就意味着它们必须包括标头文件、宣布 Pthreads 数据结构、并调用 Pthreads 指定的函数。基本上,此流程与使用其它库没有不一样。和 UNIX 以及 Linux 上的其它库同样,Pthreads 库只是简单地连接到应用代码(经过 -lpthread 参数)。

虽然 Pthreads 库至关复杂(尽管不像一些其它固有的 API 设置那样普遍)并且显然具备便携性,可是所有固有线程 API 经常使用的严格限制条件也使它很是艰难:它须要大量线程专用代码。换言之,为 Pthreads 进行编码就要在线程模型中创建代码库,这是不可回避的。此外,一些决策(如须要使用的线程数据)也将成为程序中的硬编码。做为这些限制的交换条件,Pthreads 能提供对于线程操做的普遍控制--这是一个固有的低级 API,一般要求多个步骤来执行简单的线程任务。例如,使用线程循环来经过大型数据块须要宣布线程结构、单首创建线程、计算通向每一个线程的循环并分配到线程、最终处理线程终止--全部这些必须由开发人员进行编码。若是循环不只仅是简单的叠代,则线程指定代码的数量将显著增长。为了公平起见,对于如此多代码的需求存在于全部本地线程 API 中,而不只仅是 Pthreads。

鉴于须要执行直接操做的线程代码的数量,开发人员一直在寻找更简单的 Pthreads 替代品。 程序员


OpenMP 是什么?

1997 年,一些厂商携手合做,在硬件制造商 Silicon Graphics 的支持下组成了新的线程接口。他们共同的问题是主要的时间操做系统所有利用了彻底不一样的线程编程方法。UNIX 使用 Pthreads、Sun 使用 Solaris 线程、Windows 使用本身的 API、而 Linux 则使用 Linux 线程(直到其后来采用 Pthreads)。委员会但愿设计出可以支持代码库不须要改变便可在 Windows 和 UNIX/Linux 上平等运行的 API。1998 年,它提供了第一个称为 OpenMP 的 API 规范(在这些日子里,“开放”这个词汇与多厂商支持的概念相关,是指开放系统,而不是如今的开放源代码的含义。)

OpenMP 规范包括 API、一组编译指示、以及对 OpenMP 指定环境变量的几种设置。随着对标准的进一步修订,OpenMP 最实用的特性之一就是那一组编译指示,这一点逐渐明朗。经过明智地使用这些编译指示,单线程程序不须要向 API 或环境变量求助便可实现多线程。经过 OpenMP 2.0 的最新版本,OpenMP 架构审核委员会(ARB)是提出 OpenMP 规范的委员会的正式名称,显然开发人员使用编译指示而不是 API 做为优先选择。让咱们来更深刻地审视这种方法,从翻新编译指示开始。

如下关于编译指示的定义(摘自微软的文档)是最清晰的解释之一:“#pragma 指示为每一个编译器提供了一种方法,可以提供机器指定和操做系统指定特性,同时保留与 C 和 C++ 语言的总体兼容性。根据定义,编译指示是机器指定或操做系统指定的,一般全部的编译器都不一样。编译指示最经常使用于 C 和 C++ 中,格式以下:#pragma token-string

编译指示的主要方面是若是编译器不能识别指定的编译指示,则它必须忽略(根据 ANSI C 和 C++ 标准)。所以,将库指定的编译指示放入代码中是安全的,不须要担忧若是采用不一样的工具包进行编译会将代码破坏。

图 1 显示了简单的 OpenMP 编译指示行动。 算法

				
01 #pragma omp parallel for
02  
03 for ( i = 0; i < x; i++ )
04  
05 {
06  
07 printf ( "Loop number is %d%d%d
08  
09 ",
10  
11 i, i, i );
12   
13 }


图 1. 经过简单的 OpenMP 编译指示实现循环的线程化

这种编译指示告诉编译器:之后的for 循环应该实现多线程化,并且线程应该并行执行。简单的解释就是:在编译器完成的工做与 OpenMP 库之间,for 循环将使用大量线程来执行。OpenMP 将致力于建立线程、经过在线程间划分交互做用来实现 for 循环的线程化、以及在 for 循环完成后处理线程。

虽然 OpenMP 不保证推理将建立多少线程,可是它一般选择等于可用执行管线数量的数量。在标准多处理器环境中,这一数量就是处理器的数量。在采用含超线程(HT)技术的处理器的系统上,管线的数量是处理器数量的两倍。API 函数或环境变量可用于撤销默认的线程数量。

OpenMP 将提供大量其它的编译指示来识别须要进行线程化的代码块、在线程中共享的范围变量或本地化到单独线程,到同步线程,如何安排任务或循环叠代到线程,等等。所以,最终它将经过线程功能提供中等级别纹理型控制。这种级别的纹理对于许多高性能计算(HPC)应用而言已经足够,在便携性和最佳执行能力的前提下,OpenMP 可以提供比大多数其它选择更好的选择,尤为是最大限度减小对于代码库的干扰。 编程


哪种线程模型适合您?

OpenMP 很是方便,由于它不会将软件锁定在事先设定的线程数量中。此类锁定工做给使用低级 API(如 Pthreads 或 Win32)的线程应用提出了一个大问题。当运行在更多处理器可用的平台上时,使用这些 API 编写的软件如何扩充线程的数量?一种方法一直是使用线程池(threading pool),其中在程序启动时建立一束线程,将工做分配到线程上。然而,这种方法须要至关多的线程指定代码,并且不能保证可以随着可用处理器的数量而合理地进行扩充。经过 OpenMP,不须要指定数量。

OpenMP 的编译指示还有另外一项重要优点:经过禁用 OpenMP 支持,代码可用做为单一线程应用进行编译。当调试程序时,以这样的方式编译代码拥有巨大优点。若是没有这种选择,开发人员会常常发现很难说明复杂的代码是否可以正确工做,由于线程问题或由于与线程无关的设计错误。

若是开发人员须要精细纹理的控制,则他们可使用 OpenMP 的线程 API。其中包括一小组函数,分为如下三个领域:查询执行环境的线程资源并设置当前的线程数量;设置、管理并释放锁来解决线程之间的资源访问;和一个小型的定时接口。使用这种 API 让人失望,由于它会取走纯编译指令方法提供的优点。在这个级别上,OpenMP API 是 Pthreads 提供的功能的一个小子集。这两个 API 都具备便携性,可是 Pthreads 能提供更大范围的原函数(primitive function),从而对线程化操做提供精细纹理的控制。所以,在必须单独管理线程的应用中,Pthreads 或本地的线程化 API(如 Windows 上的 Win32)将是更加天然的选择。

为了运行 OpenMP,开发人员必须促使编译器支持标准。在 Linux 和 Windows 上,面向 C/C++ 和 Fortran 的英特尔? 编译器支持 OpenMP。在 UNIX 平台上,SGI、Sun、惠普和 IBM 都提供兼容 OpenMP 的编译器。开放源代码版本经过 Omni OpenMP Compiler 项目提供,网址为http://www.hpcs.cs.tsukuba.ac.jp/omni-openmp/*。

所以,若是您正在为高性能计算(HPC)编写 UNIX 或 Linux 应用,则应该关注 Pthreads 和 OpenMP。您可能会发现 OpenMP 是一款不错的解决方案。 api


资源

Dave Butenhof,《POSIX 线程编程》 (Addison-Wesley, 1997年)。

Rich Gerber 和 Andrew Binstock,《超线程技术编程》(英特尔出版社,2004 年)。

Bil Lewis,《多线程编程教育》
http://www.lambdacs.com/*

Pthreads Win32, http://sources.redhat.com/pthreads-win32/*

开始使用 OpenMP*

OpenMP* 高级编程

英特尔? 线程处理工具和 OpenMP* 安全


做者简介

15529_binstockphoto.jpgAndrew Binstock 现任 Pacific Data Works LLC 首席分析师。此前他曾担任普华永道(PricewaterhouseCoopers)公司的高级技术分析师,以及《UNIX Review》《C Gazette》的前任主编。他是《Practical Algorithms for Programmers(程序员实用算法)》(Addison-Wesley Longman 出版)的主要做者,该书目前已经是第 12 次印刷,普遍应用于美国 30 多个计算机科学部门。 服务器



<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>
阅读(978) | 评论(0) | 转发(0) |
0

上一篇:OPENMP之hello微信

下一篇:双核,超线程的区别数据结构

给主人留下些什么吧!~~
评论热议