简介

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

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

Pthreads 概述

线程是什么?

  • 从技术角度讲,一个线程是一个独立的指令流可以被操作系统调用运行。But what does this mean?
  • 从程序员的角度讲,独立于主程序而单独运行的“程序”可以被称为一个线程。
  • 更进一步的讲, 想象一个包含很多子程序的主程序 (a.out) . 然后想象所有这些子程序都能操作系统调用同时并且独立的运行。这就是一个多线程的程序。
  • 这是怎么完成的呢?
  • 在理解线程之前, 先要理解UNIX系统下的进程。 一个进程是由操作系统创建的, 并且要求大量的"开销"。进程包含关于程序资源的信息和程序的执行状态,包括:
    • 进程ID,进程组ID, 用户ID,和组ID
    • 环境
    • 工作目录
    • 程序指令
    • 寄存器
    • 文件描述符
    • 信号操作
    • 共享库
    • 进程通信工具 (例如消息队列,管道,信号量,或者共享内存 ).

UNIX进程                                                                                              线程

  • 线程使用并存在在这些进程资源中,线程可以被操作系统调用并独立运行, 很大程度上是因为它只复制了很少量的作为可执行代码存在的必须重要资源。

  • 一个线程完成独立的控制流是因为它维护自己拥有的:

    • 栈指针
    • 寄存器
    • 调度优先级
    • 待定和阻塞信号集合
    • 线程特有的数据
  • 因此,简而言之,在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,但是,在主线程建立其他线程之后,就各自工作

共享内存模型:

  • 所有线程都可以访问相同的全局,共享内存
  • 线程可以由自己的私有数据
  • 程序员应该负责同步全局共享的数据的访问

线程安全

  • 线程安全:
  • 举例,假设你的程序创建一些线程,每个线程都调用相同的子程序:
    • 这个子程序访问或者更改一个全局结构或者一个全局变量
    • 由于每个线程都调用这个子程序,所以它们可能同时尝试修改这个全局结构或者全局变量
    • 如果这个子程序没有使用某种同步方法来防止数据崩溃的话,这个程序就不是线程安全的

POSIX 线程编程(一)简介的更多相关文章

  1. 在 POSIX 线程编程中避免内存泄漏

    检测和避免 POSIX 线程内存泄漏的技巧 POSIX 线程(pthread)编程定义了一套标准的 C 编程语言类型.函数和常量 — 且 pthreads 提供了一种强大的线程管理工具.要充分使用 p ...

  2. Posix线程编程指南

    Posix线程编程指南 Posix线程编程指南... 1 一线程创建与取消... 2 线程创建... 2 1.线程与进程... 2 2. 创建线程... 2 3. 线程创建属性... 2 4. 创建的 ...

  3. Posix线程编程指南(2)

    这是一个关于Posix线程编程的专栏.作者在阐明概念的基础上,将向您详细讲述Posix线程库API.本文是第2篇将向您讲述线程的创建与取消. 一.概念及作用在单线程程序中,我们经常要用到"全 ...

  4. Posix线程编程指南(3)

    这是一个关于Posix线程编程的专栏.作者在阐明概念的基础上,将向您详细讲述Posix线程库API.本文是第三篇将向您讲述线程同步. 一.互斥锁尽管在Posix Thread中同样可以使用IPC的信号 ...

  5. Posix线程编程指南(1)

    这是一个关于Posix线程编程的专栏.作者在阐明概念的基础上,将向您详细讲述Posix线程库API.本文是第一篇将向您讲述线程的创建与取消.   一.线程创建 1.1 线程与进程相对进程而言,线程是一 ...

  6. Posix线程编程指南(5)

    Posix线程编程指南(5) 杨沙洲 原文地址:http://www.ibm.com/developerworks/cn/linux/thread/posix_threadapi/part5/ 杂项 ...

  7. Posix线程编程指南(4)

    Posix线程编程指南(4) 杨沙洲 原文地址:http://www.ibm.com/developerworks/cn/linux/thread/posix_threadapi/part4/ 线程终 ...

  8. Posix线程编程指南(4) 线程终止

    线程终止方式 一般来说,Posix的线程终止有两种情况:正常终止和非正常终止.线程主动调用pthread_exit()或者从线程函数中return都将使线程正常退出,这是可预见的退出方式:非正常终止是 ...

  9. Posix线程编程指南(5) 杂项

    在Posix线程规范中还有几个辅助函数难以归类,暂且称其为杂项函数,主要包括pthread_self().pthread_equal()和pthread_once()三个,另外还有一个LinuxThr ...

随机推荐

  1. ASP.NET中的Webconfig 和 Global.asax区别

    Web.Config与Global.asax的区别: Config可以根据不同的错误类型定义不同的错误页,网站重定义转向新的错误页面. Global,在全局错误中写入应用程序事件错误信息,并在当前页输 ...

  2. html 页面刷新

    JS 脚本 方法1 setInterval 函数 定时局部刷新用到jQuery里面的setInterval方法, 该函数每隔一段时间请求一次数据,然后将请求结果返回给前端HTML实现刷新. setIn ...

  3. Codeforces Round #269 (Div. 2) B. MUH and Important Things

    It's time polar bears Menshykov and Uslada from the zoo of St. Petersburg and elephant Horace from t ...

  4. 利用POI操作不同版本号word文档中的图片以及创建word文档

    我们都知道要想利用java对office操作最经常使用的技术就应该是POI了,在这里本人就不多说到底POI是什么和怎么用了. 先说本人遇到的问题,不同于利用POI去向word文档以及excel文档去写 ...

  5. java应用集锦9:httpclient4.2.2的几个常用方法,登录之后访问页面问题,下载文件

    转账注明出处:http://renjie120.iteye.com/blog/1727933 在工作中要用到android,然后进行网络请求的时候,打算使用httpClient. 总结一下httpCl ...

  6. 基础apache命令

    在启动Apache服务之前,可以使用下面的命令来检查配置文件的正确性. C:\Apache2.2\bin> httpd  -n  Apache2.2  -t 还可以通过命令行控制Apache服务 ...

  7. SQL常用函数集锦

    ..STUFF()用另一子串替换字符串指定位置.长度的子串.STUFF (<character_expression1>, <start_ position>, <len ...

  8. 洛谷P4012 深海机器人问题(费用流)

    题目描述 深海资源考察探险队的潜艇将到达深海的海底进行科学考察. 潜艇内有多个深海机器人.潜艇到达深海海底后,深海机器人将离开潜艇向预定目标移动. 深海机器人在移动中还必须沿途采集海底生物标本.沿途生 ...

  9. Python3字符串 详解

    Python3 字符串 字符串是 Python 中最常用的数据类型.我们可以使用引号('或")来创建字符串. 创建字符串很简单,只要为变量分配一个值即可. Python 访问字符串中的值 P ...

  10. SQL Server-聚焦聚集索引对非聚集索引的影响

      前言 在学习SQL 2012基础教程过程中会时不时穿插其他内容来进行讲解,相信看过SQL Server 2012 T-SQL基础教程的童鞋知道前面写的所有内容并非都是摘抄书上内容,如若是这样那将没 ...