Blaise Barney, Lawrence Livermore National Laboratory
目录表
- 摘要
- 译者序
- Pthreads 概述
- Pthreads API编译多线程程序
- 线程管理
- 互斥量(Mutex Variables)
- 条件变量(Condition Variable)
- 没有覆盖的主题
- Pthread 库API参考
- 参考资料
| 摘要 |
在多处理器共享内存的架构中(如:对称多处理系统SMP),线程可以用于实现程序的并行性。历史上硬件销售商实现了各种私有版本的多线程库,使得软件开发者不得不关心它的移植性。对于UNIX系统,IEEE POSIX 1003.1标准定义了一个C语言多线程编程接口。依附于该标准的实现被称为POSIX theads 或 Pthreads。
该教程介绍了Pthreads的概念、动机和设计思想。内容包含了Pthreads API主要的三大类函数:线程管理(Thread Managment)、互斥量(Mutex Variables)和条件变量(Condition Variables)。向刚开始学习Pthreads的程序员提供了演示例程。
适于:刚开始学习使用线程实现并行程序设计;对于C并行程序设计有基本了解。不熟悉并行程序设计的可以参考EC3500: Introduction To Parallel Computing。
| Pthreads 概述 |
什么是线程**?**
- 技术上,线程可以定义为:可以被操作系统调度的独立的指令流。但是这是什么意思呢?
- 对于软件开发者,在主程序中运行的“函数过程”可以很好的描述线程的概念。
- 进一步,想象下主程序(a.out)包含了许多函数,操作系统可以调度这些函数,使之同时或者(和)独立的执行。这就描述了“多线程”程序。
- 怎样完成的呢?
- 在理解线程之前,应先对UNIX进程(process)有所了解。进程被操作系统创建,需要相当多的“额外开销”。进程包含了程序的资源和执行状态信息。如下:
- 进程ID,进程group ID,用户ID和group ID
- 环境
- 工作目录
- 程序指令
- 寄存器
- 栈
- 堆
- 文件描述符
- 信号动作(Signal actions)
- 共享库
- 进程间通信工具(如:消息队列,管道,信号量或共享内存)
| Unix Process | Process-thread relationship |
| UNIX PROCESS | THREADS WITHIN A UNIX PROCESS |
- 线程使用并存在于进程资源中,还可以被操作系统调用并独立地运行,这主要是因为线程仅仅复制必要的资源以使自己得以存在并执行。
- 独立的控制流得以实现是因为线程维持着自己的:
- 堆栈指针
- 寄存器
- 调度属性(如:策略或优先级)
- 待定的和阻塞的信号集合(Set of pending and blocked signals)
- 线程专用数据(TSD:Thread Specific Data.)
- 因此,在UNIX环境下线程:
- 存在于进程,使用进程资源
- 拥有自己独立的控制流,只要父进程存在并且操作系统支持
- 只复制必可以使得独立调度的必要资源
- 可以和其他线程独立(或非独立的)地共享进程资源
- 当父进程结束时结束,或者相关类似的
- 是“轻型的”,因为大部分额外开销已经在进程创建时完成了
- 因为在同一个进程中的线程共享资源:
- 一个线程对系统资源(如关闭一个文件)的改变对所有其它线程是可以见的
- 两个同样值的指针指向相同的数据
- 读写同一个内存位置是可能的,因此需要成员显式地使用同步
| Pthreads 概述 |
什么是 Pthreads?
- 历史上,硬件销售商实现了私有版本的多线程库。这些实现在本质上各自不同,使得程序员难于开发可移植的应用程序。
- 为了使用线程所提供的强大优点,需要一个标准的程序接口。对于UNIX系统,IEEE POSIX 1003.1c(1995)标准制订了这一标准接口。依赖于该标准的实现就称为POSIX threads 或者Pthreads。现在多数硬件销售商也提供Pthreads,附加于私有的API。
- Pthreads 被定义为一些C语言类型和函数调用,用pthread.h头(包含)文件和线程库实现。这个库可以是其它库的一部分,如libc。
| Pthreads 概述 |
为什么使用 Pthreads?
- 使用Pthreads的主要动机是提高潜在程序的性能。
- 当与创建和管理进程的花费相比,线程可以使用操作系统较少的开销,管理线程需要较少的系统资源。
例如,下表比较了fork()函数和pthread_create()函数所用的时间。计时反应了50,000个进程/线程的创建,使用时间工具实现,单位是秒,没有优化标志。
备注:不要期待系统和用户时间加起来就是真实时间,因为这些SMP系统有多个CPU同时工作。这些都是近似值。
| 平台 | fork() | pthread_create() | ||||
| real | user | sys | real | user | sys | |
| AMD 2.4 GHz Opteron (8cpus/node) | 41.07 | 60.08 | 9.01 | 0.66 | 0.19 | 0.43 |
| IBM 1.9 GHz POWER5 p5-575 (8cpus/node) | 64.24 | 30.78 | 27.68 | 1.75 | 0.69 | 1.10 |
| IBM 1.5 GHz POWER4 (8cpus/node) | 104.05 | 48.64 | 47.21 | 2.01 | 1.00 | 1.52 |
| INTEL 2.4 GHz Xeon (2 cpus/node) | 54.95 | 1.54 | 20.78 | 1.64 | 0.67 | 0.90 |
| INTEL 1.4 GHz Itanium2 (4 cpus/node) | 54.54 | 1.07 | 22.22 | 2.03 | 1.26 | 0.67 |
- 在同一个进程中的所有线程共享同样的地址空间。较于进程间的通信,在许多情况下线程间的通信效率比较高,且易于使用。
- 较于没有使用线程的程序,使用线程的应用程序有潜在的性能增益和实际的优点:
- CPU使用I/O交叠工作:例如,一个程序可能有一个需要较长时间的I/O操作,当一个线程等待I/O系统调用完成时,CPU可以被其它线程使用。
- 优先/实时调度:比较重要的任务可以被调度,替换或者中断较低优先级的任务。
- 异步事件处理:频率和持续时间不确定的任务可以交错。例如,web服务器可以同时为前一个请求传输数据和管理新请求。
- 考虑在SMP架构上使用Pthreads的主要动机是获的最优的性能。特别的,如果一个程序使用MPI在节点通信,使用Pthreads可以使得节点数据传输得到显著提高。
- 例如:
- MPI库经常用共享内存实现节点任务通信,这至少需要一次内存复制操作(进程到进程)。
- Pthreads没有中间的内存复制,因为线程和一个进程共享同样的地址空间。没有数据传输。变成cache-to-CPU或memory-to-CPU的带宽(最坏情况),速度是相当的快。
- 比较如下:
| Platform | MPI Shared Memory Bandwidth(GB/sec) | Pthreads Worst CaseMemory-to-CPU Bandwidth (GB/sec) |
| AMD 2.4 GHz Opteron | 1.2 | 5.3 |
| IBM 1.9 GHz POWER5 p5-575 | 4.1 | 16 |
| IBM 1.5 GHz POWER4 | 2.1 | 4 |
| Intel 1.4 GHz Xeon | 0.3 | 4.3 |
| Intel 1.4 GHz Itanium 2 | 1.8 | 6.4 |
| Pthreads 概述 |
使用线程设计程序
并行编程**:**
- 在现代多CPU机器上,pthread非常适于并行编程。可以用于并行程序设计的,也可以用于pthread程序设计。
- 并行程序要考虑许多,如下:
- 用什么并行程序设计模型?
收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人
都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!