我觉得这一切都要追根溯源一下,这样可能更容易了解一下。最初的程序是没有操作系统啊,内核啊这种概念的,所有的事情都得自己来干,包括如何访问外设,如何调度任务,如何分配内存,这样有个好处是灵活,坏处就是写代码累啊,事无巨细啥都自己干,程序员本来就够忙的了。:)

对于程序员而言,最重要的能力是你的逻辑能力和抽象能力。

这时候又是发挥我们聪明才智的时候了。先辈们将这些和业务无关的东西抽象出来,做成内核,释放一些接口,其他人只需要调用这些接口就OK了,不需要关心跟硬件相关的大部分细节,也可以不太关心纷杂的硬件区别了。这里说的接口就是系统Api了,像POSIX标准。

操作系统有很多分类,比如单就如何调度任务,就有好多分类,这里需要说明一下,我们平时用的操作系统像Linux,Mac,Windows都是分时操作系统,还有另外一个比较熟悉的分类是实时操作系统,这类操作系统常用在一些特殊场景里。Google最近搞得Fuchsia OS是为嘛,因为linux系统的局限性,不能很好适应一些场景,这里的场景包括对功耗的要求,对实时响应的要求等等。市面上比较熟悉有μC/OS-II,可以看源码,有兴趣可以了解一下。

原来接触过开发COS(Chip Operating System)的同学,他们要在计算能力很差,内存很小,永久存储很小甚至没有的的单片机上开发,他们说他们的程序就是简单的循环,查看有没有事件,有事件就处理一下,但也很繁琐,内存得一个字节一个字节的算,像最早的时代的开发一样。

有时候在想要是什么开发都能搞一搞就好了,可以体会不同的乐趣,完善自己的知识体系。

内核就是搞这些事情,隔离大家不那么关心亦或不想关心得事情。


现在来说进程,上面说了进程调度也是内核负责的事情。进程的产生源自性能的过剩,一组硬件(包括cpu,内存等),可以在一定的时间完成几件事情,比如我们可以在电脑上看着电影,听着歌,刷着微博,聊着QQ,前提是你的脑子能处理过来:)。

计算机在做这些事情时,希望每件事情进行的同时且互不干扰,又到先辈们发挥聪明才智的时候,私以为里面最有趣就是内存的隔离了,每个进程都有自己的地址,而且都是从0开始计算的,还不冲突(当然这只是现在的我们最常见得情况)。

对于每个进程都有一个可以称为进程描述符的数据结构记录的在内核里。

那么进程是如何调度的呢?是中断信号,中断信号一来,就会立马执行一段程序。

在最初学习计算机时,一直理解不了中断这种东西,在我想象中代码应该像瀑布一下,连续的,头也不回的执行下去,直到尽头。

但现实是残酷的,还有中断这种东西,它一来正在运行的代码就干不下去了,就像我在写代码,这时领导过来了,开会。

中断来了后,各种寄存器的里值都会被保存起来,包括正在计算的值,运行到的位置,所谓保护现场。

然后将另外一个曾经被保存过的进程,重新装载,然后就像催眠大师一样打个响指,就可以继续运行了。

这里面有个曾经很困惑的概念,就是内核代码和用户区代码,所谓用户区代码就是你写的代码,内核代码就是内核里的代码(废话)。

在查看进程的运行时间时,也会有用户区代码运行时间,内核代码运行时间。

我的困惑在于,内核里的代码被我想象成了另外一个进程的代码。内核只是运行在优先级与用户区代码不同。

还有内核代码的作用范围也加强了我的困惑。内核里的代码可以修改别的进程的数据,权限之高,能力之大,虽然此时此刻它只是运行在当前进程描述符下。

虽然可以修改别的进程,但内核代码是别人写的,即使在你的进程下运行,但里面干啥也不是你能随心所欲的。

像进程间通信就是这样,一个进程告诉内核一个数据,内核将其记录,然后找到目的进程,再copy过去。

一个进程,另外一个进程,还有内核,构成一种三角关系,于是我就困惑了。


线程

一般面试官会问线程和进程的区别

然后我就懵逼了,可能是因为太简单了

在我眼里,线程和进程的区别在从属关系和通信方式

  1. 进程可以有多个线程

  2. 进程间的通信需通过内核,线程只需全局变量就好了嘛


协程

协程很长时间理解不了。系统内任务的调度其实是以线程为单位调度的,每个线程可以运行一定的时间,协程咋调度?难道是在更小的时间片内调度?还说协程很轻量不需要内核调度,啥意思?

后来,突然顿悟,协程,当然是协作了,肯定要协商调度了。

A协程:我运行了,你们靠后站。 A运行中。。。 A协程:我完了,你们谁来? B协程:我来 B运行中。。。 B协程:谁还在等?请继续

就像线程里有个循环,不断从一个列表寻找正在等待运行代码,正在运行的代码需要等待一个其他条件就放回去。有点像线程池。

协程的调度在用户态,无需内核参与。协程的调度在于主动让出,以及可恢复。

进入了多核时代,这种模式很吃香啊,所以erlang火了,go火了。想想一个线程里可以运行多段业务代码,多有趣。

在单核里多协程的好处恐怕就只有减少点内核里调度的消耗,所以erlang诞生了这么多年才走出原来的小圈子。在那个时代多核只在电信行业的服务器才有吧。