前言
进程(process)和线程(thread)是操作系统的基本概念,也是平常编程的过程中,我们经常遇到和听到的名词
由于上大学的时候,老师在讲解有关线程、进程课程时,我应该在玩《神庙逃亡》,所以这一方面一直不是很扎实
就在最近,我读到了国外的一篇文章和阮一峰博士的文章,这两篇文章利用‘车间’和‘工人’的关系来类比,浅显易懂,分享给大家
概念
计算机的核心是CPU,它承担了所有的计算任务。它就像一座工厂,时刻在运行。
进程
假定工厂的电力有限,一次只能供给一个车间使用。也就是说,一个车间开工的时候,其他车间都必须停工
背后的含义就是,单个CPU一次只能运行一个任务
进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。 简单来说,一个进程就是一个执行中的程序,它在计算机中一个指令接着一个指令地执行着,同时,每个进程还占有某些系统资源如CPU时间,内存空间,文件,文件,输入输出设备的使用权等等。换句话说,当程序在执行时,将会被操作系统载入内存中。
线程
一个车间里,可以有很多工人。他们协同完成一个任务。线程就好比车间里的工人。
背后的含义就是,一个进程可以包括多个线程
线程与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中可以产生多个线程。与进程不同的是同类的多个线程共享同一块内存空间和一组系统资源,所以系统在产生一个线程,或是在各个线程之间作切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程。
共享内存
车间的空间是工人们共享的,比如许多房间是每个工人都可以进出的。
背后的含义就是,这象征一个进程的内存空间是共享的,每个线程都可以使用这些共享内存
互斥锁
可是,每间房间的大小不同,有些房间最多只能容纳一个人,比如厕所。里面有人的时候,其他人就不能进去了。这代表一个线程使用某些共享内存时,其他线程必须等它结束,才能使用这一块内存。一个防止他人进入的简单方法,就是门口加一把锁。先到的人锁上门,后到的人看到上锁,就在门口排队,等锁打开再进去。
“互斥锁”(Mutual exclusion,缩写 Mutex),防止多个线程同时读写某一块内存区域
信号量
还有些房间,可以同时容纳n个人,比如厨房。也就是说,如果人数大于n,多出来的人只能在外面等着。这好比某些内存区域,只能供给固定数目的线程使用。这时的解决方法,就是在门口挂n把钥匙。进去的人就取一把钥匙,出来时再把钥匙挂回原处。后到的人发现钥匙架空了,就知道必须在门口排队等着了。
这种做法叫做”信号量”(Semaphore),用来保证多个线程不会互相冲突。
不难看出,mutex是semaphore的一种特殊情况(n=1时)。也就是说,完全可以用后者替代前者。但是,因为mutex较为简单,且效率高,所以在必须保证资源独占的情况下,还是采用这种设计。
优先级
如果卫生间目前已锁定并且有许多人正在等待使用它怎么办?显然,所有的人都坐在外面,等待浴室里的任何人出去。真正的问题是,“当门解锁时会发生什么?谁下次去?“
你会认为允许等待时间最长的人接下来是“公平的”。或者,让最老的人走向下一步可能是“公平的”。或者最高。或者最重要的。有很多方法可以确定什么是“公平的”。
我们通过两个因素来解决这个问题:优先级和等待时间。
假设两个人同时出现在(锁定的)浴室门口。其中一个人有一个紧迫的截止日期(他们已经迟到了会议),而另一个则没有。让紧迫的截止日期的人下一步是不是有意义?嗯,当然会。唯一的问题是你如何决定谁更“重要”。 这可以通过分配优先级来完成(让我们使用像Neutrino这样的数字 - 一个是最低的可用优先级,255是此版本中最高的优先级)。房屋内有紧迫期限的人将获得更高的优先权,而那些没有最后期限的人将被赋予较低的优先权。
线程也一样。线程从其父线程继承其调度算法,但可以调用 pthread_setschedparam() 来更改其调度策略和优先级(如果它有权执行此操作)。
如果有多个线程在等待,并且互斥锁被解锁,我们会将互斥锁提供给具有最高优先级的等待线程。但是,假设两个人都有同样的优先权。那你现在怎么办?那么,在这种情况下,允许等待时间最长的人下一步是“公平的”。这不仅是“公平的”,而且也是Neutrino内核的作用。在一堆线程等待的情况下,我们主要通过优先级,其次 是等待的长度。
互斥锁肯定不是我们遇到的唯一同步对象。我们来看看其他一些。
操作系统的设计,因此可以归结为三点:
(1)以多进程形式,允许多个任务同时运行;
(2)以多线程形式,允许单个任务分成不同的部分运行;
(3)提供协调机制,一方面防止进程之间和线程之间产生冲突,另一方面允许进程之间和线程之间共享资源。
进程和线程简单而基本靠谱的定义如下:
- 进程:程序的一次执行
- 线程:CPU的基本调度单位