POSIX 线程编程(一)简介

简介


在共享内存的多处理器结构中,能够用线程来实现并行。对于UNIX系统, IEEE POSIX 1003.1c标准规定了C语言线程编程接口的标准。这份标准的实现就是POSIX threads, 或者称为Pthreads.node

本文开始先介绍线程的基本概念,动机和设计方面的一些考虑。 接下来是Pthreads API 的三个主要部分:线程管理,互斥锁和 条件变量。本文自始至终会贯穿大量的示例代码来展现如何使用Pthread API的每一部分。程序员

Pthreads 概述

线程是什么?

  • 从技术角度讲,一个线程是一个独立的指令流能够被操做系统调用运行。But what does this mean?

     

  • 从程序员的角度讲,独立于主程序而单独运行的“程序”能够被称为一个线程。

     

  • 更进一步的讲, 想象一个包含不少子程序的主程序 (a.out) . 而后想象全部这些子程序都能操做系统调用同时而且独立的运行。这就是一个多线程的程序。

     

  • 这是怎么完成的呢?
  • 在理解线程以前, 先要理解UNIX系统下的进程。 一个进程是由操做系统建立的, 而且要求大量的"开销"。进程包含关于程序资源的信息和程序的执行状态,包括:
    • 进程ID,进程组ID, 用户ID,和组ID
    • 环境
    • 工做目录
    • 程序指令
    • 寄存器
    • 文件描述符
    • 信号操做
    • 共享库
    • 进程通讯工具 (例如消息队列,管道,信号量,或者共享内存 ).

                                    UNIX进程                                                                                              线程web

 

  • 线程使用并存在在这些进程资源中,线程能够被操做系统调用并独立运行, 很大程度上是由于它只复制了不多量的做为可执行代码存在的必须重要资源。编程

  • 一个线程完成独立的控制流是由于它维护本身拥有的:安全

    • 栈指针
    • 寄存器
    • 调度优先级
    • 待定和阻塞信号集合
    • 线程特有的数据
  • 所以,简而言之,在UNIX系统环境中一个线程:多线程

    • 存在在一个进程中并使用进程资源
    • 只要父进程存在而且操做系统支持就一直拥有本身独立的控制流
    • 仅复制独立调度所必须关键资源
    • 能够和其余线程共享进程资源
    • 若是线程的父进程死掉,则该线程死掉
    • 是“轻量级”的由于大可能是开销在它的进程建立的时候已经完成了
  • 同一进程的线程间共享资源,致使:并发

    • 一个线程对于共享的系统资源所作的更改(例如关闭一个文件)将会被全部其余的线程发现
    • 两个具备相同值的指针指向相同的数据
    • 可能读写相同的内层位置,所以要求程序员进行显式的同步

为何使用线程

  • 在高性能计算的世界,使用线程的首要目的是实现潜在的程序性能的提高
  • 与建立和管理进程的花费相比,建立一个线程只须要较少的系统开销。管理线程所须要的系统资源原少于管理进程异步

    举例来讲,下表是fork() 与 pthread_create()所花时间的对比。     工具

 

Platform fork() pthread_create()
real user sys real user sys
Intel 2.6 GHz Xeon E5-2670 (16 cores/node) 8.1 0.1 2.9 0.9 0.2 0.3
Intel 2.8 GHz Xeon 5660 (12 cores/node) 4.4 0.4 4.3 0.7 0.2 0.5
AMD 2.3 GHz Opteron (16 cores/node) 12.5 1.0 12.5 1.2 0.2 1.3
AMD 2.4 GHz Opteron (8 cores/node) 17.6 2.2 15.7 1.4 0.3 1.3
IBM 4.0 GHz POWER6 (8 cpus/node) 9.5 0.6 8.8 1.6 0.1 0.4
IBM 1.9 GHz POWER5 p5-575 (8 cpus/node) 64.2 30.7 27.6 1.7 0.6 1.1
IBM 1.5 GHz POWER4 (8 cpus/node) 104.5 48.6 47.2 2.1 1.0 1.5
INTEL 2.4 GHz Xeon (2 cpus/node) 54.9 1.5 20.8 1.6 0.7 0.9
INTEL 1.4 GHz Itanium2 (4 cpus/node) 54.5 1.1 22.2 2.0 1.2 0.6

  • 一个进程中的全部线程共享相同的地址空间。在不少状况下线程间通讯比进程间通讯更高效和容易。性能

  • 线程应用与非线程应用相比,提供的潜在的性能提高和实际的优点主要经过如下几种方法:

    • 经过I/O重叠CPU工做:
    • 优先/实时调用:更重要的任务能够优先调用或者中断低优先级的任务
    • 异步事件处理:服务不肯定频率和交叉存取的事件的任务。举例来讲,一个web服务端程序能够在和一个请求传送数据的同时管理新到的请求

设计线程程序

并行编程

  • 设计并行程序须要考虑不少方面:
    • 使用什么类型的并行编程模型
    • 问题分解
    • 负载平衡
    • 通讯
    • 数据依赖关系
    • 同步和竞争条件
    • 内存问题
    • I/O问题
    • ...
  • 本文将不对上述问题进行深刻的探讨,不过,感兴趣的能够戳这里:Introduction to Parallel Computing
  • 通常来说,一个程序想要发挥Pthread的优点,必须是能够分离成独立的能够同时运行的子任务 如图所示:
  • 适合使用Pthread的程序通常由以下性质:
    • 工做能够被多任务同时执行或者数据能够被同时操做
    • 潜在的长时间I/O等待阻塞
    • 必须响应异步事件
    • 一些工做比其余的工做更重要(优先级中断)
  • 一些常见的基于线程的程序模型:
    • Manager/worker:manager线程分配任务给其余workers线程。
    • Pipeline:一个任务被分红一系列的子任务,每一个子任务都被一个不一样的线程有序并发的处理。相似汽车装配线
    • Peer:有点相似Manager/worker,可是,在主线程创建其余线程以后,就各自工做

共享内存模型:

  • 全部线程均可以访问相同的全局,共享内存
  • 线程能够由本身的私有数据
  • 程序员应该负责同步全局共享的数据的访问 

线程安全

  • 线程安全:
  • 举例,假设你的程序建立一些线程,每一个线程都调用相同的子程序:
    • 这个子程序访问或者更改一个全局结构或者一个全局变量
    • 因为每一个线程都调用这个子程序,因此它们可能同时尝试修改这个全局结构或者全局变量
    • 若是这个子程序没有使用某种同步方法来防止数据崩溃的话,这个程序就不是线程安全的 
相关文章
相关标签/搜索