进程(process)就是操作系统的灵魂,一个软件的程序通常就是由若干进程组成的。现在计算机一般采用多道程序设计和多处理机设计(所谓的4核、八核其实就是指多个处理机)。
一、并行和并发
并行:就是由多个CPU情况下,多道程序可以在同一时刻依靠不同CPU运行,注意是同一时刻,而不是时间间隔,这就是并行性。
并发:现在我们假设只有一个CPU,那么多道程序要运行,必然在同一时刻只有一个才可以占用CPU,而计算机让CPU在同一时间段内快速地在多道程序间交换,注意这里是同一时间间隔,这样就造成了一种伪并行的感觉,这就是并发性。
二、进程和程序的区别
进程和程序很容易被混淆。可以举一个简单例子,例如一位科学家,买了食谱和一些面粉等原材料准备给他女儿做蛋糕。那么食谱上蛋糕的做法就是程序(即被适当描述的算法),科学家就是CPU,那么科学家按照食谱上的做法,结合面粉这些原料做蛋糕的过程这就是进程了。总的来说,程序是静态的,就是一堆代码。进程是动态的,更强调一系列动作的总和。单个处理机经常被多个进程共享,它使用某种调度算法决定进程间的切换。
三、进程的创建和终止
进程的创建,通常是由一个已经存在的进程执行了创建进程的系统调用而创建了一个新的进程。这个已经存在的进程可能是一个由键盘或鼠标启动的系统进程、一个已经存在的用户进程,或一个批处理管理进程。这个进程的工作就是执行一个创建进程的系统调用,这个系统调用就会通知操作系统创建一个新进程,并且直接或间接地指定在该进程中运行的程序。(fork程序就是用来创建一个进程的,通常调用该程序所得到的子进程是父进程的一个副本,但是拥有独立的地址空间,需要执行一个execve或类似的系统调用,修改存储映像以用来运行别的程序)。总的来说,记住进程通常由三种方式(系统程序调用系统调用、用户程序调用系统调用、批处理管理程序调用系统调用)创建
进程的终止,通常有四个原因:1、正常退出(自愿,exit),2、出错退出(自愿),3、严重错误(非自愿),4、被其他进程杀死(非自愿,kill)。
四、进程调度
要理解进程调度,必须先知道进程一般情况下有三个状态:
运行态:正在占有处理器正在运行;
阻塞/等待态:等待某个事件的完成;阻塞队列
就绪态:等待系统分配处理器以便运行。就绪队列
运行态---->阻塞态/等待态:通常是由于等待外设IO操作,因为IO操作比起CPU高速运算来说慢的多得多,CPU不可能把这些时间都让这个程序在占有着CPU的情况下在等待,因此将该进程转换为阻塞态,至于阻塞队列中。同理等待主存资源也是一个原因。说白了之所以切换到等待态就是为了等待某个相对CPU来说慢的多的事件的完成。
阻塞态--->就绪态:等待的条件已完成,那么进程就从阻塞队列转到了就绪队列,只需等待CPU分配处理器即可。
就绪态---->运行态:系统按某种策略选中一个处于就绪状态的进程,使其获得处理机并执行。
运行态--->就绪态:时间片用完或者被抢占,让出CPU。不是由于自身原因,而是由于外部原因导致。
进程调度算法(就是从就绪队列中选取哪个进程进入运行态的策略):先进先出算法、短进程优先算法、轮转法、多级反馈队列。说白了获取资源就可以摆脱等待态。
五、进程(process)和线程(控制流、thread)
在有些情况下,需要在相同的地址空间中有多个控制流并行得运行,就像他们是单独的进程一样(只是他们共享相同的地址空间),通常这些控制流就被称为线程,或者轻量级进程。
举个简单例子,就是我们访问一个web页面时,对于web页面上的每一幅小图像,浏览器都必须与站点建立一个连接。这种情况下,就可以采用多线程,让浏览器可以同时传输多幅图像。
线程和进程一样,也有三种状态。
总的来说,线程就是控制流,多线程就比如web页面读取多个图片时的机制。线程是CPU调度的最小单位,进程是资源分配的最小单位(因为一般情况下,多个线程公用一个人由进程所获取的地址空间。)
六、同步机制
临界资源、临界区(critical section)、互斥量(mutex)、信号量(samaphore)、事件(event)
临界资源:比如例如打印机、磁带机这种就属于临界资源
1)临界区(critical section):临界区就是访问公共资源的一段代码。通常如果一个线程执行到了临界区代码,那么其他视图访问公共资源的线程将被挂起,直到该线程离开这段代码区。这样就保证了任意时刻只有一个线程访问公共资源,就不会造成异步的不定向问题。但这个只能在同一个应用程序的不同线程间实现资源的安全共享。因为只有属于本程序的才能检测到临界区是否在执行。
2)互斥量(mutex):即互斥对象,只有一个,只有拥有互斥对象的线程才有访问公共资源的权限。因此这样也保证了资源的安全共享。但是互斥量比临界区负载,且比临界区复杂以及功能强大,它可以在不同应用程序的线程之间实现对资源的安全共享。
3)信号量(samaphore):它允许多个线程同时访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目,即。这与操作系统的PV操作相同。
PV操作:
P操作申请资源:S-1;若S-1>=0,则进程执行执行;若S-1<0,则该进程被阻塞后进入该信号相对应的队列中,然后转入进程调度;
V操作释放资源:S+1;若S+1>0,则进程继续执行。若S+1<=0,则从该信号的等待队列中唤醒一个等待进程,然后再返回原进程继续执行或转入进程调度。
4)事件:通过通知操作的方式来保持线程的同步,还可以方便实现对多个线程的优先级比较的操作。
七、进程通信
进程通信主要包括管道,IPC(包括消息队列,信号量,共享存储),socket
(1)管道:管道分为有名管道和无名管道,无名管道只能用于父子进程之间的通信,而有名管道则可用于无亲属关系的进程之间。
(2)消息队列:用于运行在同一台机器上的进程间通信,与管道相似;
(3)共享内存:通常由一个进程创建,其他进程对这块内存进行读写。并不常用
(4)信号量:计数器,它用来记录对某个资源的存取状况。
(5)socket:应用于不同计算机的进程通信。
八、进程通信和同步区分。
进程同步:临界区、互斥量、信号量、事件
进程通信: 管道、消息队列(事件)、共享存储、信号量、socket
相同点:两者都有信号量和消息队列(事件)
九、死锁(deallocks)
概念:死锁就是指两个后两个以上的进程(线程)在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,他们将无法推进下去。由于资源占用是互斥的,当某个资源提出资源申请后,使得有关进程在无外力协助下,永远无法分配不到必需的资源而无法继续执行,这就产生了一种特殊现象的死锁。
产生死锁的四个必要条件:
互斥条件:一个资源只能被一个进程(线程)使用
请求和保持条件:一个进程(线程)因请求资源而阻塞时,对已获得的资源保持不放
不剥夺条件:此进程(线程)已获得的资源,在未使用完之前,不能强行剥夺
循环等待条件:多个进程(线程)之间形成一种头尾相接的循环等待资源关系。
死锁的预防:
因为第一个条件是天然的,因此可以选择破坏后三个死锁的条件其中一个实现对死锁的预防。
- 破坏请求和保持条件:
一次性请求所需的所有资源,若无法获取全部就等待,直到满足为止。
2.破坏不可剥夺条件
规定一个已占用资源的额进程若要申请新的资源,必须先释放自己已占用的资源;
3.破坏循环等待条件
将系统中所有的资源设置标志位、排序,规定所有的进程申请资源必须以一定的(升序或降序)做操作。(这个就是解决了哲学家就餐问题)