进程状态&&调度算法&&进程线程区别&&进程通信方式&&线程同步

来源:互联网 发布:网络控制器没有驱动 编辑:程序博客网 时间:2024/06/01 23:41

一、进程有哪几种状态?画出状态转换图。

这里写图片描述

  1. 进程就绪—>进程调度(13)—>执行
  2. 进程执行—>时间轮片用尽/被抢占—>就绪
  3. 进程阻塞—>事件发生—>就绪
  4. 进程执行—>事件请求—>阻塞
  5. 在linux系统下有一种进程的状态叫做僵死状态,这种状态是由于子进程已经退出但是父进程没有回收子进程造成的,(因为子进程结束时往往会给父进程发一个SIGCHILD信号,所以在网络编程中为了防止忘记回收子进程,而造成将死进程的出现,一般都会捕捉SIGCHILD信号,在信号处理函数中,回收子进程。

二、进程的调度算法

  1. 先来先服务调度算法:

    每次调度都从进程就绪队列中选择一个最先进入该队列的进程优先调度

  2. 短进程优先调度算法:

    从就绪队列中选一个估计运行时间最短的进程,分配处理机

  3. 优先权调度算法:
      在进程调度的时候,把处理机分配个就绪队列中优先权最高的进程

    1. 非抢占式优先权调度算法
        系统一旦把处理机分配给就绪队列中优先权最高的进程,该进程就会一直执行下去,直到进程执行完毕,或者有事件发生,使得该进程放弃处理机为止,系统才可以再将处理机分配给另一个优先权最高的进程——>主要用于对实时性要求不高的系统中。
    2. 抢占式优先权调度算法:
        系统同样将处理机分配给优先权最高的进程,但是在进程执行期间若出现了更高优先级的进程,则原来正在执行的进程会从执行态变为就绪态,系统将处理机分配给更高优先级的进程。——>能够更好地满足紧迫作业的要求,一般用于比较严格的实时系统中。
  4. 高响应比优先算法:

      引入动态优先权使进程的等待时间的增加而提高,则进程在等待一段时间后必然有机会分配到处理机。
      Rp=响应时间/要求服务时间
      如果进程的等待时间相同,则要求服务时间越短,优先权越高,类似于短进程优先
      如果进程要求服务时间相同则优先权取决于等待时间,等待时间越长,优先权越高。

  5. 时间片轮转算法:

    先按照先来先服务排队,再将处理机分配给队首进程,若时间片用尽则将其中断,并放至队尾

  6. 多级反馈队列调度算法:

    1. 设置多个队列,并为各个队列赋予不同的优先级,第一个队列优先级最高,然后依次逐级降低,优先级越高的队列队列中的时间片越小,优先级越低的时间片越大
    2. 当一个新进程进入系统后,先将他当做第一个队列的队尾,按照先来先服务的规则等待调度,如果新的进程能够在时间片用尽之前执行完成,则撤离系统,否则放到第二个队列的队尾
    3. 仅当第一个队列空闲时,调度程序才调度第二个队列里的进程。

三、进程与线程的区别

  1. 进程是系统进行资源分配的基本单位(有独立的地址空间),线程是系统调度的基本单位(没有独立的地址空间,但是有独立的栈,局部变量、寄存器和程序计数器)
  2. 进程创建的开销比线程大,因为每次创建一个进程时,都要为其分配虚拟地址空间,而创建线程基本只需要一个内核对象,和一个栈。
  3. 一个进程无法直接访问另一个进程的资源,如果需要通信则进程之间需要同时看到一片公共资源,如可以通过管道、信号量、共享内存、消息队列、套接字等实现进程间通信,而线程之间通信很容易,因为他们共享很多东西,如全局变量、堆空间。
  4. 进程间切换开销大,线程间切换开销小

    进程切换比线程切换开销大是因为进程切换时要切页表,而且往往伴随着页调度,因为进程的数据段代码段要换出去,以便把将要执行的进程的内容换进来。(虚拟地址空间也要重新映射)本来进程的内容就是线程的超集。而且线程只需要保存线程的上下文(相关寄存器状态和栈的信息)就好了,动作很小

  5. 线程属于进程,一个线程死了这个进程就会挂掉,进程中的其他线程也会挂掉,但是一个进程死了对其他的进程基本无影响。
  6. 什么时候使用进程什么时候使用线程?
    进程与线程的选择取决以下几点:
    1. 需要频繁创建销毁的优先使用线程;因为对进程来说创建和销毁一个进程代价是很大的。
    2. 线程的切换速度快,所以在需要大量计算,切换频繁时用线程,还有耗时的操作使用线程可提高应用程序的响应
    3. 因为对CPU系统的效率使用上线程更占优,所以可能要发展到多机分布的用进程,多核分布用线程;
    4. 并行操作时使用线程,如C/S架构的服务器端并发线程响应用户的请求;
    5. 需要更稳定安全时,适合选择进程;需要速度时,选择线程更好。

三、进程间通信的几种方式

  1. 管道

    管道是一种半双共的通信方式,数据只能单向流动,并且只能在具有亲缘关系的进程间通信。管道只能传送无格式字节流。

  2. 有名管道

    有名管道也是一种半双共的通信方式但是他可以在无亲缘关系的进程间实现通信。

  3. 信号量

    信号量是一个计数器,可以控制多个进程对共享资源的访问,他常常作为一种锁机制,防止进程在访问资源时,其他进程也访问该资源。

  4. 消息队列

    是由消息构成的链表,存放在内核中,并以消息队列标示符标示,克服了信号传递信息少,管道只能传输无格式字节流的缺点。

  5. 共享内存

    共享内存是最快的IPC方式原因如下:

    在Linux进程间通信的方式中,共享内存是一种最快的IPC方式。因此,共享内存用于实现进程间大量的数据传输,共享内存的话,会在内存中单独开辟一段内存空间,这段内存空间有自己特有的数据结构,包括访问权限、大小和最近访问的时间等。
    为什么说共享内存是最快的一种IPC方式呢?让我们一起来看一下下面的这张图:
    这里写图片描述
    从这张图中,我们可以看出,使用管道(FIFO/消息队列)从一个文件传输信息到另外一个文件需要复制4次。一是,服务器端将信息从相应的文件复制到server临时缓冲区中;二是,从临时缓冲区中复制到管道(FIFO/消息队列);三是,客户端将信息从管道(FIFO/消息队列)复制到client端的缓冲区中;四是,从client临时缓冲区将信息复制到输出文件中。
    这个是对于不是共享内存的其他方式的消息传送过程,下面我们仔细来看一下对于共享内存而言,这种消息传送机制是怎样的呢?我们还是先看一下下面这张图:
    这里写图片描述
    从这张图中,我们可以看出,共享内存的消息复制只有两次。一是,从输入文件到共享内存;二是,从共享内存到输出文件。这样就很大程度上提高了数据存取的效率

  6. 套接字

    多用于不同主机进程间的通信。

四、线程同步的几种方式(生产者消费者模型)

  1. 临界区

      多个线程通过串行化访问一片公共资源,或一段代码,实现线程间同步,速度快,适合控制数据访问。
      在一个时刻只允许一个线程对公共资源进行访问,如果有多个线程试图访问该公共资源,那么再有一个线程进入后,其它试图访问公共资源的线程将被挂起,并一直等到进入临界区的线程离开。

  2. 互斥量

    采用互斥对象机制,只有拥有互斥对象的线程才有访问公共资源的权限,因为互斥对象只有一个,所以能够保证公共资源不会同时被多个线程访问。

  3. 信号量

    允许多个线程在同一时刻访问公共资源但是要限制同一时刻访问此资源的最大线程数目

  4. 事件

    通过事件通知的方式实现线程间的同步

    基于环型队列的生产者消费者模型#include<stdio.h>#include<pthread.h>#include<semaphore.h>#define SIZE 60int databuf[SIZE]sem_t blanks;sem_t datas;pthread_mutex_t conslock=PTHREAD_MUTEX_INITIALIERpthread_mutex_t proclock=PTHREAD_MUTEX_INITIALIERvoid * producer(){    static int i=0;    for(;;)    {        sem_wait(blanks);        pthread_mutex_lock(&proclock);        databuf[i]=rand()%1000;        i++;        sem_post(datas);        pthread_mutex_unlock(&proclock);    }    return NULL;}void *consumer(){    static int i=0;    for(;;)    {        sem_wait(&datas);        pthread_mutex_lock(&conslock);        int data=databuf[i];        i++;        i%=SIZE;        sem_post(&blanks);        pthread_mutex_lock(&conslock);    }    return NULL;}int main(){    sem_init(&blanks,0,SIZE);    sem_init(&datas,0,0);    pthread_t producer_id1,consumer_id1;    pthread_t producer_id2,consumer_id2;    pthread_create(&producer_id1,NULL,producer,NULL);    pthread_create(&consumer_id1,NULL,consumer,NULL);    pthread_join(producer_id1,NULL);    pthread_join(consumer_id1,NULL);    pthread_join(producer_id2,NULL);    pthread_join(consumer_id2,NULL);    pthread_join(producer_id1,NULL);    sem_destroy(&blanks);    sem_destroy(&datas);}

    http://blog.csdn.net/zsf8701/article/details/7844316

    五、线程的实现方式

    线程的实现方式可以分为用户级线程内核级线程

    用户级线程指不需要内核支持而是在用户程序层面实现的线程,其实现不依赖于操作系统核心,应用程序利用相应的线程库提供创建,同步、调度和管理线程的函数来控制用户级线程,用户级线程内核的切换由用户态程序自己控制内核切换,不需要内核干涉,少了进出内核态的消耗,但不能很好的利用多核Cpu,目前Linux pthread大体是这么做的
    优点:不需要用户态和核心态的频繁切换,所以速度快,操作系统感知不到多线程的存在
    缺点:一个线程阻塞会导致整个进程阻塞,因为事实上还是以进程为调度的基本单位的。
    内核级线程由操作系统内核创建和撤销,内核维护进程及线程上下文信息,及线程的切换,一个内核线程由于IO操作阻塞,不影响其他线程


对比:
1. 内核级线程是OS内核可感知的,而用户级线程是OS内核不可感知的。
2. 用户级线程的创建、撤销和调度不需要OS内核支持,是在语言层面 实现的,而内核级线程的创建和调度都需要OS内核支持。
3. 用户级线程在执行系统调用命令时会导致其所属进程被中断,二内核支持的线程只会导致该线程被中断。
4. 只有用户级线程的操作系统中实际调度还是以进程为单位,在有内核支持的则以线程为单位。


内核线程的优点:

(1)当有多个处理机时,一个进程的多个线程可以同时执行。

缺点:

(1)由内核进行调度。

用户进程的优点:

(1) 线程的调度不需要内核直接参与,控制简单。

(2) 可以在不支持线程的操作系统中实现。

(3) 创建和销毁线程、线程切换代价等线程管理的代价比内核线程少得多。

(4) 允许每个进程定制自己的调度算法,线程管理比较灵活。这就是必须自己写管理程序,与内核线程的区别

(5) 线程能够利用的表空间和堆栈空间比内核级线程多。

(6) 同一进程中只能同时有一个线程在运行,如果有一个线程使用了系统调用而阻塞,那么整个进程都会被挂起。另外,页面失效也会产生同样的问题。

缺点:

(1)资源调度按照进程进行,多个处理机下,同一个进程中的线程只能在同一个处理机下分时复用

六、用户态和内核态的区别

   用户态和内核态是操作系统的两种运行级别,当程序运行在3级特权级时可以称之谓,程序运行在用户态,因为这是最低特权级,是普通用户的特权级,当我们在操作系统中执行程序的时候大部分是运行在这种状态下的,在其需要操作系统完成某些他没有权限完成的事情时,会切换的内核态具体有一下三种情况
  1.系统调用
  2.异常
  3.外围设备中断
内核态和核心态的主要差别是:
处于用户态时,进程所能访问的内存空间有限制,其所占有的处理机是可以被抢占的,而处于核心态的进程,其所访问的内存空间没有现场,其所占有的处理机是不可抢占的。

原创粉丝点击