天天看点

重学操作系统原理系列 - 进程管理(一)六、线程

六、线程

6.1 线程的引入

引入理由

  • 应用的需要
  • 开销的考虑
  • 性能的考虑

6.1.1 应用的需要

我们看一个例子,一个

web

服务器的工作方式

  • 从客户端接收网页请求
  • 从磁盘上检索相关的网页,读入内存(此时进程是停止的,直到读取完毕)
  • 将网页返回给对应的客户端

可以看到每次从磁盘读取的时候进程都是暂停的,这样会导致性能低下

那如何提高服务器的工作效率?通常情况下是使用网页缓存

没有线程情况下的两种解决方案

  • 一个服务进程undefined这种情况下也是一种顺序编程,虽然采用了缓存机制,但是性能同样不高。而如果设置多个进程,这多个进程之间又是相互独立的,有独立的地址空间,所以不能共享信息
  • 有限状态机undefined这种方式编程模型复杂,采用非阻塞的

    I/O

多线程的解决方式

重学操作系统原理系列 - 进程管理(一)六、线程

**说明:**这是一个多线程的

web

服务器的工作方式,首先读取客户端的请求,之后由分派线程将各个任务分派给工作线程,这里还是采用了网页缓存

于是我们可以看到一个

web

服务器的实现有三种方式:

重学操作系统原理系列 - 进程管理(一)六、线程

6.1.2 开销的考虑

重学操作系统原理系列 - 进程管理(一)六、线程

6.1.3 性能的考虑

如果有多个处理器的话,一个进程就会有多个线程同时在执行了,这样可以极大的提高运行性能

6.2 线程的基本概念

重学操作系统原理系列 - 进程管理(一)六、线程

线程的属性

  • 有标识符

    ID

  • 有状态及状态转换

    -->

    需要提供一些操作
  • 不运行时需要保存的上下文(程序计数器等寄存器)
  • 有自己的栈和栈指针
  • 共享所在进程的地址空间和其他资源
  • 创建、撤销另一个线程(程序开始是以一个单线程方式运行的)

6.3 线程机制的实现

一般有三种实现机制

  • 用户级线程
  • 核心级线程
  • 混合(两者结合)方法6.3.1 用户级线程
重学操作系统原理系列 - 进程管理(一)六、线程

说明:线程是由运行时系统管理的,在内核中只有进程表。典型例子就是

UNIX

undefinedPOSIX线程库–PTHREAD

重学操作系统原理系列 - 进程管理(一)六、线程

优点

  • 线程切换快
  • 调度算法是应用程序特定的
  • 用户级线程可运行在任何操作系统上(只需要实现线程库)

缺点

  • 内核只将处理器分配给进程,同一进程中的两个线程不能同时运行于两个处理器上
  • 大多数系统调用是阻塞的,因此,由于内核阻塞进程,故进程中所有线程也被阻塞。(可以在调用之前判断进行解决,如果是阻塞线程,那么就换其他线程)6.3.2 核心级线程
重学操作系统原理系列 - 进程管理(一)六、线程
  • 线程创建在用户空间完成
  • 线程调度等在核心态完成
  • 例子如

    Solaris

    操作系统

6.4 线程状态(Java)

0)新建:创建后尚未启动的线程处于这种状态。

1)运行:包括了 OS 中 Running 和 Ready 状态,也就是处于此状态的线程可能正在运行,也可能正在等待 cpu 为它分配执行时间

2)无限期等待:处于这种状态的线程不会被分配 cpu 执行时间,要等待其他线程显示唤醒。以下方法会让线程进入无限期等待 :

  • 没有设置 timeout 的 object.wait()
  • 没有设置 timeout 参数的 Thread.join()
  • LockSupport.park()

3)有限期的等待:处于这种状态的线程也不会被分配 cpu 执行时间,不过无需等待被其他线程显示唤醒,而是在一定时间后,他们会由 OS 自动唤醒 1.设置了 timeout 的 object.wait() 方法 2. 设置了 timeout 参数的 Thread.join() 3.LockSupport.parkNanos()

4.LockSupport.parkUnit()

4) 阻塞:与"等待"的区别:

  • 阻塞态在等待获取一个排它锁,这个事件将在另外一个线程放弃这个锁的时候发生
  • 等待状态在等待一段时间或者唤醒动作。

5)结束:已终止线程的线程状态,线程已经结束执行。 进程的通信类型

  • 共享存储器、管道、客户机-服务器系统(socket)
  • 直接通信、间接通信(信箱)