回眸进程和线程

在上一篇文章中,我们简单地回眸了一下操作系统,这一次我们细致一点来回眸一下进程和线程,通过这样的回眸,也许能膨胀出一些火花,对进程和线程有个比以往更清晰明了的认识。我们还是从问题的角度出发,帮助我们分析一下进程和线程。注意下诉讨论都在单核CPU的范围内,多核会有些出入。

为什么要有进程和线程?

回答这个问题之前,我们先看看我们手机上常用的应用,这些应用可能有一个或者多个进程。这些应用在运行时往往会用到不同的资源,占用着各自的内存,互相独立而又互相竞争。是不是很有趣的关系?看起来这些应用里面的进程,帮助我们隔离了不同的资源,管理着各自应用的运行状态。我们可以这么称呼进程,资源分组大师。实际上,操作系统里面的进程也确实是从这样的角度上来定义的,用某种方法将相关资源集合起来

那么有了进程之后,为什么还要有线程呢?线程有悖于进程,是从不同的角度出发考虑的。前者是从资源分组的角度出发,线程则是从执行的角度上看的。有了进程分组后的资源后,要知道怎么利用这些资源呀。所以就需要有线程,而且每个进程必须要有一个线程作为执行单元。

process_and_thread

那为什么要有多进程和多线程呢?

我们用户都是享乐主义的,我刷刷微博的同时就不能听听音乐吗?多进程很好理解,这是用户的主观要求。对于操作系统而言就是,容许多个资源集合同时被处理。那为啥需要多线程呢?这更多地需要从效率的角度上出发,毕竟用户是不知道你内部是如何实现的。我们搞开发的都知道,用户所感知到的是 UI 线程,如果在 UI 线程上面等待某个网络的返回,那么势必会卡顿。多线程就是给予应用本身并发的能力。

多进程和多线程的原理是什么?

在只有 单核CPU 的情况下,CPU 真的在同一时间内只会执行一个程序。那怎么办呢?这里我们引入分时的概念。例如我们将每一秒分为很多个片段,在相邻的片段里面执行的不同的进程,这样从用户感知的角度上看,就是同时运行了多个程序。对于线程而言,它是具体执行的单位,在每个时段执行的是这一线程。

为了达成这一目标,就需要有两件时间要完成。通知进程中断,和进程中断及恢复。前者的问题是通过 时钟 来的,这不是一般的时钟,我们也不用太细致地去理解,知道通过这个通知就可以了。进程的恢复,则需要我们记录相应的东西,我们称为程序计数器。另一方面,线程也有同样类似的机制,也有程序计数器、寄存器等等。

那么接下来,就有另外的问题了,大多数进程和线程都是要合作的。

  1. 信息如何传递?

  2. 如何保证信息安全?

  3. 如何保证时序性要求?

简单地说下这三个问题。第一是如何解决信息共享,信息到底怎么传递到另一个进程(线程)上去。信息安全是,当多个进程(线程)同时访问数据时,怎么能保证这些进程(线程)获得正确的数据。时序是指当两个执行单元有依赖要求时,如何保证执行的顺序。

信息传递

对于线程而言,这一块是天生支持的。因为所有线程都共享同一地址空间,只要能拿到对象的句柄,那么哪个线程都可以访问得到。进程就不一样了,需要借助第三方的工具来完成。主要是共享内存,管道Socket。具体机制不讨论,可以理解为操作系统开辟了一块区域,两个进程都能访问。Socket 则是通过协议的方式,要求接受者在没有消息的时候进行等待,来完成通信协议,从而传递消息的。

同步

安全和时序,这里都可以通过同步来完成。大家在 Android 开发中已经接触不少了。这里简单地提提进程方面的同步,毕竟接触得不如线程间同步来得多。进程间同步的问题,大多都是由中断信号引起的,在最早期的思路里面,做法特别简单粗暴。在执行某个有同步风险的代码时,屏蔽中断,这样就不会发生进程切换,问题自然就没有了。哈哈,这样的弊端实在太多,没过多久就被抛弃了。后期采用了信号量的实现,这也是 Dijkstra 提出的哦。信号量类似于 Java 中的 CountDownLatch,不过信号量是进程级别的,有兴趣的同学可以看看。互斥量则是简化版的信号量,233333。

总结与絮叨

又大致地回眸了一下,进程和线程,有没有觉得思路清晰了一些呢。至少我是这么认为的,:)。欢迎老师同学来交流,多多批评指正。有兴趣的同学可以看看,哲学家就餐问题,读者-写者问题。

哲学家就餐问题


文档信息


Published: February 06 2017