标签:
进程就是处于执行期的程序。但进程并不仅仅是一段可执行的代码。通常进程还要包含其它资源,像进程标识符,打开的文件,接收到的信号,处理器状态,所分配的内存等信息。实际上,进行就是正在执行程序代码的实时结果,内核需要有效而又透明地管理所有的细节,所以一个进程需要维护非常多的信息。所以总的来说,进程就是处于执行期的程序以及相关资源信息的总称。
Linux中,用一个task_struct结构体来表示一个进程。
线程也叫轻量级进程,是进程中活动的对象,一个进程包含多个线程。每个线程都拥有独立的程序计数器(存放下一条指令所在的地址)、线程栈和一组寄存器(线程切换时,需要记录寄存器的状态,即记录上下文)。内核调度的对象是线程,而不是进程。而进程是资源分配的单位,同一个进程中的所有线程共享该进程的所有资源。
先有进程,然后才发展出了线程,所以进程的各种知识一般都适用于线程。
操作系统原理中,进程有三种基本的状态。
就绪(Ready)状态:进程已经万事俱备,只欠CPU了。只要一获得CPU就可以执行。
执行(Running)状态:进行正在进行。
阻塞(Block)状态:正在执行的进程期待某个事件的发生,但是该事件(例如键盘输入数据、其它进程发来的数据等)没有发生,那么就会阻塞。当事件发生时,该进程就会被唤醒。
下面是三种状态的转换图
有下 述基类事件会引起进程的阻塞或者唤醒。
(1)向系统申请共享资源失败,此时进程不能继续运行而转为阻塞状态,知道资源被释放,该进程才被唤醒。比如请求使用打印机。
(2)等待某种操作的完成,当进程启动某种操作后,如果该进程必须在该操作完成之后才能继续执行,则应该将该线程阻塞起来。例如进程启动了某I/O设备,如果只有在I/O设备完成指定的I/O操作任务之后才能继续进程,则该进程在启动I/O设备后便进去阻塞状态。具体的一个例子就是等待控制台的输入。
(3)新数据尚未到达,对于相互合作的进程,如果一个进程需要获取另一进程提供的数据才能对数据进程处理,只要其所需要的数据尚未到达,进程便只有阻塞。
(4)等待新任务的到达,某些进程处理完特定任务后就把自己阻塞起来,然后等待新任务的到来。比如服务器等待客户端发来请求,然后处理该请求。
临界资源:一次只能由一个进程访问的资源称为临界资源。
临界区:程序中访问临界资源的代码叫做临界区。
为了做到对临界资源的互斥访问,每个进程在进入自己的临界区时,需要对想要访问的临界资源进行检查,看它是否正在被访问。可以使用信号量机制来保证对临界区的互斥访问。信号量分为整形信号量和记录型型号量。
(1)整型信号量
整型信号量需要两个原子操作(Atomic operation)的支持,wait(S)和signal(S),S是整型,表示某临界资源的数目,所以称作整型信号量。
wait(S){ while(S<=0);//不断轮询,直到S>0,即资源可访问时,才退出循环 S--; } signal(S){ S++; }
在进入临界区之前调用wait(S)操作,在退出临界区之前调用signal(S)操作,即可做到对临界资源的互斥访问。但是wait(S)操作中,只要信号量S<=0,那么就会不断轮询,直到条件满足。这样很浪费CPU资源,效率不高。所以引进了记录型信号量。
(2)记录型信号量
记录型信号量是一个结构体,它不止维护了一个整数表示某临界资源的数目,而且维护了一个进程链表。
typedef struct{ int value;//某临界资源的数目 struct task_struct *list; }semaphore;
记录型信号量需要四个原子操作的支持,wait(S),signal(S),block(S),wakeup(S)。
wait(semaphore *S){ S->value--; if(S->value<0) block(S->list);//说明临界资源正在被其它进程访问,那么就阻塞当前进程 } signal(semaphore *S){ S->value++; if(S->value<=0) wakeup(S->list);//S->value<=0说明队列中有阻塞的进行,所以唤醒其中的一个 } //进程是阻塞到关于该信号量的队列中去。
wait操作中,如果S->value<0,说明已经没有资源可以使用了,于是将进程阻塞到与信号量S相关的阻塞队列中去。
signal操作中,如果S->value<=0,说明当前阻塞队列中还有被阻塞的进程,所以唤醒其中的一个进行。
该文章在我的个人博客的地址:http://www.alphaway.org/post-406.html
参考:
标签:
原文地址:http://www.cnblogs.com/beMaster/p/5374353.html