进程与线程

1.引入线程的背景

我们知道进程的两个基本属性:

进程是一个拥有资源的独立单元;
进程同时又是一个可以被处理器独立调度和分配的单元。 

总的来说,为了使多个程序更好地并发执行,并尽量减少操作系统的开销,操作系统设计者引入了线程,让线程去完成第二个基本属性的任务,而进程只完成第一个基本属性的任务。

事实上,进程控制块就是为了让各个进程之间能够给很好的隔离。但是有的场景下,多进程的隔离性设计不满足实际需求,举个例子:

我们现在有一个mp3播放程序,它可以分为三部分:

while(true)
{
    Read();//IO读数据
    Decompress();//CPU解压数据
    Play();//播放
}

如果这样写的话,IO和CPU不断的切换,资源使用率低下,而且播放出来的声音可能不连贯。(上一波数据缓冲已经播放完,下一波的数据还没有到达)那么改成多进程呢?

//程序一
while(true)
{
    Read();//IO读数据
}
//程序二
while(true)
{
    Decompress();
}

//程序三
while(true)
{
    Play();
}

可是问题是这三个进程怎么通信,共享数据呢? 两个进程之间的通信要通过系统调用从内核中绕一圈,如果都在一个进程中就好了。

另外多进程也会加大系统开销:创建进程、销毁进程、切换进程等。

所以线程就应运而生了。

线程是进程内部的一类实体,满足以下两个特性;

1)实体之间可以并发执行

2)实体之间共享相同的内存地址空间

有了线程之后,我们把相关的执行流的信息变成线程控制块,它所为进程控制块的新的一部分。这样,在线程控制块中就可以有多个指令指针、多个堆栈和多个CPU寄存器的现场保护,这些都和执行流相关。如下图:

线程 = 进程 - 资源共享

多进程的缺点:

  1. 创建进程的过程开销大
  2. 为了完成进程间的数据交换,需要特殊的IPC技术

所以为了保持多进程的优点,并在一定程度上客服其缺点,引入线程。它的优点是:

  1. 线程创建和上下文切换比进程更快
  2. 线程间数据交换无需特殊技术

线程的定义

线程是进程内一个相对独立的、可调度的执行单元。线程自己基本上不拥有资源,只拥有一点在运行时必不可少的资源(如程序计数器、一组寄存器和栈),但它可以与同属一个进程的其他线程共享进程拥有的全部资源。多线程是指一个进程中有多个线程,这些线程共享该进程资源。但是各线程自己堆栈数据不对其他线程共享。

2.进程和线程的关系

  • 进程是操作系统进行资源分配的基本单位
  • 线程是调度的基本单位

进程中的所有线程共享该进程的状态和资源,进程和线程的关系如下图:

例如QQ 和浏览器是两个进程,浏览器进程里面有很多线程,例如 HTTP 请求线程、事件响应线程、渲染线程等等,线程的并发执行使得在浏览器中点击一个新链接从而发起 HTTP 请求时,浏览器还可以响应用户的其它事件。

二者具体的区别:

Ⅰ 拥有资源

进程是资源分配的基本单位,但是线程只有和指令执行流相关的必要资源,如寄存器和栈等,线程可以访问隶属进程的资源。

Ⅱ 调度

线程是独立调度的基本单位,在同一进程中,线程的切换不会引起进程切换,从一个进程中的线程切换到另一个进程中的线程时,才会引起进程切换。

Ⅲ 系统开销

由于创建或撤销进程时,系统都要为之分配或回收资源,如内存空间、I/O 设备等,所付出的开销远大于创建或撤销线程时的开销。类似地,在进行进程切换时,涉及当前执行进程 CPU 环境的保存及新调度进程 CPU 环境的设置,而线程切换时只需保存和设置少量寄存器内容,开销很小。

Ⅳ 通信方面

线程间可以通过直接读写同一进程中的数据进行通信,但是进程通信需要借助 IPC。

二者的侧重点

进程为了使同一台计算机上可以运行多道不相关联的任务,而线程的引入主要目的在于提高同一个任务完成的效率。

3.看看本质

我们知道,每个内存有自己独立的内存空间,包括保存全局变量的数据区,供动态分配使用的堆区,函数运行时使用的栈区。

但如果以获得多个代码执行流为主要目的,则不需要向上面那样完全分离内存结构,只需要分离栈区域就可以。这样可以获得如下优势:

  1. 上下文切换不需要切换数据区和堆;
  2. 可以利用数据区和堆交换数据(通信);

 实际上这就是线程,线程为了保持多条代码执行流而隔离了栈区域,它的内存结构如下:

为了保持上图中,多个线程共享数据区和堆的结构,线程将在进程中创建并运行。即,进程和线程可以定义为如下形式:

  • 进程:在OS中构成单位执行流的单位;
  • 线程:在进程中构成单独执行流的单位

如果说在OS中生成了多个执行流即多进程的话,那么在同一进程内部创建多个执行流就是多线程了。OS、进程和线程的关系可以表示成下图:

4.线程的生命周期

线程的一些状态: 
1、新建:创建线程对象 
2、就绪:线程有执行资格,没有执行权 
3、运行:有执行资格,有执行权 
4、阻塞:由于一些操作让线程改变了状态,没有执行资格,没有执行权 
另一些操作可以把它给激活,激活处于就绪状态 
5、死亡:线程对象变成垃圾,等待被回收

 5.线程的分类

线程可以分为用户级线程、内核线程。

5.1用户级线程

是用户通过自己写的线程库来完成线程的管理,包括线程的创建、终止、调度等。操作系统并不会感知用户态中有多线程的支持。

优点:

  1. 不依赖于操作系统内核;
  2. 同一进程内的用户线程切换速度快;
  3. 允许每个进程有自己的线程调度算法;

缺点:

  1. 线程发起系统调用而阻塞时,则整个进程将进入等待;
  2. 不支持基于线程的处理机抢占:除非当前运行线程主动放弃,它所在的线程无法抢占CPU;
  3. 操作系统按进程分配CPU时间片,所以多个线程中,每个线程的时间片较少; 

5.2 内核级线程

是由内核通过系统调用方式实现的线程机制,由内核完成线程的创建,终止和管理。 

特点:

  1. 将由内核完成PCB和TCB;
  2. 线程执行系统调用而被阻塞不影响其他线程;
  3. 线程的创建、终止和切换开销相对较大
  4. 可以以线程为单位进行CPU时间分配
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值