zl程序教程

您现在的位置是:首页 >  其他

当前栏目

期末复习——线程

2023-04-18 15:21:27 时间

MEMO

  1. 多线程下的fork():有的复制所有线程;有的仅仅复制了调用fork()的线程。
  2. 多线程下的exec():指定的程序会取代整个进程,包括所有线程。

多核编程

  • 并发性:单核系统只有并发,------->

  • 并行性:多核同时执行

  • 程序员面对的挑战:

    • 识别任务:查找独立、并发的任务
    • 平衡:有些任务不值得用一个单核来运行
    • 数据分割
    • 测试与调试
  • 并行类型

    • 数据并行:将数据分布于多核。
      e.g.核0(0-n)、核1(n+1 - 2n)这种
    • 任务并行:将线程(task任务)分布在多核上。
      e.g.线程1:算数组A一行的和、线程2:算数组A一列的和

Amdahl 定律

N核处理器,S比例为串行部分,(1-S)部分为并行部分
加速比 <= 1/(S + (1-S)/N)

线程

CPU运行调度的基本单位。

  • 多线程进程内的线程私有:线程ID

    • 寄存器
  • 多线程进程内的线程共享

    • 、代码段、数据段(全局变量)、打开文件列表
      image
  • 多线程编程优点:响应性、资源共享、经济(创建、切换线程消耗更小)、可伸缩性

  • 用户线程管理:线程库(程序员)、隐式多线程(转移管理权给编译器/运行时库)

  • 内核线程管理:内核

1.多线程模型

  • 多线程创建策略
    • 异步线程:非阻塞,父子线程并发执行,父进程创建完就恢复执行。so很少有数据共享。
    • 同步线程:阻塞,等待所有子进程终止父进程才恢复执行。

1.1多对一模型

多用户线程(一般是一个进程内的) 映射到 一个内核线程。线程调度管理都在用户空间
每次只允许一个线程映射。

  • 优:线程管理都在用户空间,效率高
  • 缺:一个线程访问内核时阻塞了,整个进程都阻塞了。
    一个时间段只有一个线程可以访问内核,不能并行运行在多核系统

1.2一对一模型

一个用户线程 映射到 一个内核线程。

  • 优:并发能力强,一个线程阻塞不影响其他线程。
  • 缺:开销很大。所以一般会限制内核线程数量。

1.3多对多模型

也可称为双层模型。克服了前两个的缺点。
在用户线程和内核线程中间加一个数据结构--轻量级进程LWP,1个LWP与一个内核线程关联。
LWP看作一个虚拟处理器,以便程序调度运行用户线程。

  • 对单核处理器
    • CPU密集型程序:1个LWP即可
    • I/O密集型程序:可能要多个LWP。

2.线程库

为程序员提供创建、管理线程的API。

  • 实现线程库的方法
    • 构建一个用户空间的函数库:非系统调用。在用户空间提供没有内核支持的库,所有代码、数据结构都在用户空间。
    • 实现由OS直接支持的内核级库:代码、数据结构都位于内核空间。so每次调用API都会导致内核的系统调用
  • 3个主要线程库
    1. POSIX Pthreads
    2. Windows 头文件 #include <windows.h>
    3. Java
      Windows和Pthreads数据共享可以直接使用全局变量,但Java没有全局变量,通过线程传递共享对象实现。

3.隐式多线程

“转移管理权”
将多线程的创建管理交给编译器and运行时库。流行趋势。

3.1线程池

  • 主要思想:
    • 开始时创建一定量线程,加载到线程池中等待工作。
    • 有工作时唤醒线程分配任务。没有可用线程就等。
    • 完成任务后,返回池中等待工作。
  • 优点
    • 快!:用现有的比创建新线程快
    • 限制线程总数:因为有些系统不支持大量并发线程。
    • 可以用不同策略执行任务:定期执行/延迟执行等等,不用考虑创建线程的问题了。更加灵活?

3.2 OpenMP 运行时库

一组编译指令API,识别并行区域 = 识别可并行运行的代码块

  • 指令
    1. #pragma omp parallel {}:有N个核创建N个线程,然后这些线程同时执行并行区域代码。
    2. #pragma omp parallel for for(;;){}:将循环工作分给多个线程。

3.3 GCD 大中央调度

Mac OS 和 iOS采用的技术。GCD为C/C++增加了的拓展。
内部GCD线程池由POSIX线程组成。
块:^{/*内容*/}

  • 将这些块放在调度队列上。
    • 串行serial调度队列:FIFO,一次删一个,每个进程都有自己的串行队列,也叫主队列。
    • 并行concurrent调度队列(我擅自改名的,书上给了并发...但是并行统一一点md垃圾翻译):FIFO,但可以一次删除多个块。
      有三个系统级并发调度队列,低、默认、高优先级-->表示块重要性。

4.多线程问题

4.1 fork() exec()

  • fork()可能复制所有线程/只复制调用fork()的那个
  • exec()指定的程序会覆盖整个进程,包括所有线程。

4.2 信号处理

同步/异步,收到信号立即处理,只能处理一次。

  • 同步信号:非法内存访问、/0问题
    发送信号到同一进程
  • 异步信号:Ctrl+C终止进程信号(传给所有线程)、时间片到期
    发送信号给另一进程
  • 信号处理程序
    • 默认信号处理程序:由内核运行
    • 用户定义的:

4.3 线程撤销

线程完成之前终止目标线程。两种情况
回忆一下,同步--阻塞;异步--非阻塞

  • 异步撤销:另一线程直接终止目标线程
    可能不会释放必要的系统资源。
  • 延迟撤销:允许目标线程终止自己。目标线程不断检查是否应终止。

Pthreads线程撤销的3中模式:1.关闭(禁用线程撤销) 2.异步撤销 3.延迟撤销(默认)

4.4 TLS线程本地存储

指的是线程的自己的数据,虽然同进程内多线程共享数据段。
TLS!=局部变量,在多个函数调用内都可见,线程特有。

4.5调度程序激活

内核线程与用户线程库之间的一种通信方案——调度器激活。

  • 内核提供一组LWP给应用程序,应用程序调度用户线程到LWP
  • 回调:内核将特定事件通知应用程序,由回调处理程序处理。
    例如一个用户线程要阻塞时,会有回调。
  • 发完回调,内核分一个新的LWP给应用程序,这个新的LWP运行回调处理程序,保存线程阻塞状态,释放LWP
  • 回调处理程序调度另一个合适的线程在新LWP上运行。
  • 之后阻塞结束了,再回调

5. 线程调度

  • 用户线程:不可调度。由线程库管理,对OS不可见,OS可见的是用户进程
  • 内核线程:可调度
    内核采用SCS系统竞争范围调度 决定选择哪一个内核线程运行。