您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 其它文档 > POSIX线程程序设计(中文版)
POSIX多线程程序设计BlaiseBarney,LawrenceLivermoreNationalLaboratory目录表1.摘要2.Pthreads概述1.什么是线程?2.什么是Pthreads?3.为什么使用Pthreads?4.使用线程设计程序3.PthreadsAPI编译多线程程序4.线程管理1.创建和终止线程2.向线程传递参数3.连接(Joining)和分离(Detaching)线程4.栈管理5.其它函数5.互斥量(MutexVariables)1.互斥量概述2.创建和销毁互斥量3.锁定(Locking)和解锁(Unlocking)互斥量6.条件变量(ConditionVariable)1.条件变量概述2.创建和销毁条件变量3.等待(Waiting)和发送信号(Signaling)7.没有覆盖的主题8.Pthread库API参考9.参考资料摘要在多处理器共享内存的架构中(如:对称多处理系统SMP),线程可以用于实现程序的并行性。历史上硬件销售商实现了各种私有版本的多线程库,使得软件开发者不得不关心它的移植性。对于UNIX系统,IEEEPOSIX1003.1标准定义了一个C语言多线程编程接口。依附于该标准的实现被称为POSIXtheads或Pthreads。该教程介绍了Pthreads的概念、动机和设计思想。内容包含了PthreadsAPI主要的三大类函数:线程管理(ThreadManagment)、互斥量(MutexVariables)和条件变量(ConditionVariables)。向刚开始学习Pthreads的程序员提供了演示例程。适于:刚开始学习使用线程实现并行程序设计;对于C并行程序设计有基本了解。不熟悉并行程序设计的可以参考EC3500:IntroductionToParallelComputing。Pthreads概述什么是线程?技术上,线程可以定义为:可以被操作系统调度的独立的指令流。但是这是什么意思呢?对于软件开发者,在主程序中运行的“函数过程”可以很好的描述线程的概念。进一步,想象下主程序(a.out)包含了许多函数,操作系统可以调度这些函数,使之同时或者(和)独立的执行。这就描述了“多线程”程序。怎样完成的呢?在理解线程之前,应先对UNIX进程(process)有所了解。进程被操作系统创建,需要相当多的“额外开销”。进程包含了程序的资源和执行状态信息。如下:o进程ID,进程groupID,用户ID和groupIDo环境o工作目录o程序指令o寄存器o栈o堆o文件描述符o信号动作(Signalactions)o共享库o进程间通信工具(如:消息队列,管道,信号量或共享内存)UNIXPROCESSTHREADSWITHINAUNIXPROCESS线程使用并存在于进程资源中,还可以被操作系统调用并独立地运行,这主要是因为线程仅仅复制必要的资源以使自己得以存在并执行。独立的控制流得以实现是因为线程维持着自己的:o堆栈指针o寄存器o调度属性(如:策略或优先级)o待定的和阻塞的信号集合(Setofpendingandblockedsignals)o线程专用数据(TSD:ThreadSpecificData.)因此,在UNIX环境下线程:o存在于进程,使用进程资源o拥有自己独立的控制流,只要父进程存在并且操作系统支持o只复制必可以使得独立调度的必要资源o可以和其他线程独立(或非独立的)地共享进程资源o当父进程结束时结束,或者相关类似的o是“轻型的”,因为大部分额外开销已经在进程创建时完成了因为在同一个进程中的线程共享资源:o一个线程对系统资源(如关闭一个文件)的改变对所有其它线程是可以见的o两个同样值的指针指向相同的数据o读写同一个内存位置是可能的,因此需要成员显式地使用同步Pthreads概述什么是Pthreads?历史上,硬件销售商实现了私有版本的多线程库。这些实现在本质上各自不同,使得程序员难于开发可移植的应用程序。为了使用线程所提供的强大优点,需要一个标准的程序接口。对于UNIX系统,IEEEPOSIX1003.1c(1995)标准制订了这一标准接口。依赖于该标准的实现就称为POSIXthreads或者Pthreads。现在多数硬件销售商也提供Pthreads,附加于私有的API。Pthreads被定义为一些C语言类型和函数调用,用pthread.h头(包含)文件和线程库实现。这个库可以是其它库的一部分,如libc。Pthreads概述为什么使用Pthreads?使用Pthreads的主要动机是提高潜在程序的性能。当与创建和管理进程的花费相比,线程可以使用操作系统较少的开销,管理线程需要较少的系统资源。例如,下表比较了fork()函数和pthread_create()函数所用的时间。计时反应了50,000个进程/线程的创建,使用时间工具实现,单位是秒,没有优化标志。备注:不要期待系统和用户时间加起来就是真实时间,因为这些SMP系统有多个CPU同时工作。这些都是近似值。平台fork()pthread_create()realusersysrealusersysAMD2.4GHzOpteron(8cpus/node)41.0760.089.010.660.190.43IBM1.9GHzPOWER5p5-575(8cpus/node)64.2430.7827.681.750.691.10IBM1.5GHzPOWER4104.0548.6447.212.011.001.52(8cpus/node)INTEL2.4GHzXeon(2cpus/node)54.951.5420.781.640.670.90INTEL1.4GHzItanium2(4cpus/node)54.541.0722.222.031.260.67fork_vs_thread.txt在同一个进程中的所有线程共享同样的地址空间。较于进程间的通信,在许多情况下线程间的通信效率比较高,且易于使用。较于没有使用线程的程序,使用线程的应用程序有潜在的性能增益和实际的优点:oCPU使用I/O交叠工作:例如,一个程序可能有一个需要较长时间的I/O操作,当一个线程等待I/O系统调用完成时,CPU可以被其它线程使用。o优先/实时调度:比较重要的任务可以被调度,替换或者中断较低优先级的任务。o异步事件处理:频率和持续时间不确定的任务可以交错。例如,web服务器可以同时为前一个请求传输数据和管理新请求。考虑在SMP架构上使用Pthreads的主要动机是获的最优的性能。特别的,如果一个程序使用MPI在节点通信,使用Pthreads可以使得节点数据传输得到显著提高。例如:oMPI库经常用共享内存实现节点任务通信,这至少需要一次内存复制操作(进程到进程)。oPthreads没有中间的内存复制,因为线程和一个进程共享同样的地址空间。没有数据传输。变成cache-to-CPU或memory-to-CPU的带宽(最坏情况),速度是相当的快。o比较如下:PlatformMPISharedMemoryBandwidth(GB/sec)PthreadsWorstCaseMemory-to-CPUBandwidth(GB/sec)AMD2.4GHzOpteron1.25.3IBM1.9GHzPOWER5p5-5754.116IBM1.5GHzPOWER42.14Intel1.4GHzXeon0.34.3Intel1.4GHzItanium21.86.4Pthreads概述使用线程设计程序并行编程:在现代多CPU机器上,pthread非常适于并行编程。可以用于并行程序设计的,也可以用于pthread程序设计。并行程序要考虑许多,如下:o用什么并行程序设计模型?o问题划分o加载平衡(Loadbalancing)o通信o数据依赖o同步和竞争条件o内存问题oI/O问题o程序复杂度o程序员的努力/花费/时间o...包含这些主题超出本教程的范围,有兴趣的读者可以快速浏览下“IntroductiontoParallelComputing”教程。大体上,为了使用Pthreads的优点,必须将任务组织程离散的,独立的,可以并发执行的。例如,如果routine1和routine2可以互换,相互交叉和(或者)重叠,他们就可以线程化。拥有下述特性的程序可以使用pthreads:o工作可以被多个任务同时执行,或者数据可以同时被多个任务操作。o阻塞与潜在的长时间I/O等待。o在某些地方使用很多CPU循环而其他地方没有。o对异步事件必须响应。o一些工作比其他的重要(优先级中断)。Pthreads也可以用于串行程序,模拟并行执行。很好例子就是经典的web浏览器,对于多数人,运行于单CPU的桌面/膝上机器,许多东西可以同时“显示”出来。使用线程编程的几种常见模型:o管理者/工作者(Manager/worker):一个单线程,作为管理器将工作分配给其它线程(工作者),典型的,管理器处理所有输入和分配工作给其它任务。至少两种形式的manager/worker模型比较常用:静态worker池和动态worker池。o管道(Pipeline):任务可以被划分为一系列子操作,每一个被串行处理,但是不同的线程并发处理。汽车装配线可以很好的描述这个模型。oPeer:和manager/worker模型相似,但是主线程在创建了其它线程后,自己也参与工作。共享内存模型(SharedMemoryModel):所有线程可以访问全局,共享内存线程也有自己私有的数据程序员负责对全局共享数据的同步存取(保护)线程安全(Thread-safeness):线程安全:简短的说,指程序可以同时执行多个线程却不会“破坏“共享数据或者产生“竞争”条件的能力。例如:假设你的程序创建了几个线程,每一个调用相同的库函数:o这个库函数存取/修改了一个全局结构或内存中的位置。o当每个线程调用这个函数时,可能同时去修改这个全局结构活内存位置。o如果函数没有使用同步机制去阻止数据破坏,这时,就不是线程安全的了。如果你不是100%确定外部库函数是线程安全的,自己负责所可能引发的问题。建议:小心使用库或者对象,当不能明确确定是否是线程安全的。若有疑虑,假设其不是线程安全的直到得以证明。可以通过不断地使用不确定的函数找出问题所在。PthreadsAPIPthreadsAPI在ANSI/IEEEPOSIX1003.1–1995标准中定义。不像MPI,该标准不是免费的,必须向IEEE购买。PthreadsAPI中的函数可以非正式的划分为三大类:1.线程管理(Threadmanagement):第一类函数直接用于线程:创建(creating),分离(detaching),连接(joining)等等。包含了用于设置和查询线程属性(可连接,调度属性等)的函数。2.互斥量(Mutexes):第二类函数是用于线程同步的,称为互斥量(mutexes),是mutualexclusion的缩写。Mutex函数提供了创建,销毁,锁定和解锁互斥量的功能。同时还包括了一些用于设定或修改互斥量属性的函数。3.条件变量(Conditionvariables):第三类函数处理共享一个互斥量的线程间的通信,基于程序员指定的条件。这类函数包括指定的条件变量的创建,销毁,等待和受信(signal)。设置查询条件变量属性的函数也包含其中。命名约定:线程库中的所有标识符都以pthread开头RoutinePrefixFunctionalGrouppthread_线程本身和各种相关函数pthread_attr_线程属性对象pthread_mutex_互斥量pthread_mutexattr_互斥量属性对象pthread_cond_条件变量pthread_condattr_条件变量属性对象pthread_key_线程数据键(Thread-specificdatakeys)在API的设计中充满了不透明对象的概念,基本调用可以创建或修改不透明
本文标题:POSIX线程程序设计(中文版)
链接地址:https://www.777doc.com/doc-2852002 .html