操作系统-进程管理与进程同步

文章介绍了进程的基本概念,包括进程的并发执行、前驱图、进程状态以及进程控制块(PCB)。详细阐述了进程的创建、终止、阻塞/唤醒、挂起/激活等操作,以及进程同步中的信号量机制和经典同步问题如生产者-消费者问题、哲学家进餐问题。此外,还讨论了进程通信和线程的概念,强调线程作为轻量级执行体的特性以及线程的状态和同步方法。
摘要由CSDN通过智能技术生成

进程管理

基本概念

程序或作业以进程的方式并发执行的

前驱图:是一个有向无循环图 ,记为DAG。用于描述进程之间执行的前后关系(由于某种条件制约)

可以使用前驱图来表示进程执行时要存在的前驱关系,如果存在直接前驱关系的进程只能按照顺序执行。没有任何关系/没有直接前驱关系的进程是可以任意并发执行。

对于单道环境而言:程序顺序执行。(顺序性 封闭性{程序运行时独占全机资源} 可再现性{只要初始条件相同,程序执 行结果是相同的})

对于多道环境而言:程序并发执行。(间断性 失去封闭性 和 再现性)

并发 + 封闭性 -> 可再现性 (在进程切换时 进行现场的保护)

进程:是为了保证程序能够正确地并发运行(过程:动态性)而采取的一种执行方式,它也是系统进行资源分配、调度和保护的基本单位

PCB(进程控制块):在发生进程切换时,用一个PCB保存被暂停程序的运行现场--关于程序运行的一切信息和数据(新的数据结构)

进程 = PCB + 程序的代码和数据

进程是一个能够独立运行的实体和单位

进程的特征:

  1. 结构特征(PCB + 数据段 + 程序段 + 系统栈 + 用户栈)

  2. 动态性(由系统创建而产生,由系统调度执行,由系统撤销摧毁)

  3. 并发

  4. 独立性(独立运行、独立分配资源、独立接受调度的基本单位)

  5. 异步性

进程的三种基本状态

  1. 就绪状态(高级调度 由外存调入内存 系统创建进程 加入到内存的就绪对列中)

  2. 执行状态(进程在内存中获取处理机之后进行执行自身的代码)

  3. 阻塞状态(由于资源的短缺或自身的IO操作而引发阻塞)

  4. 挂起状态(由外部力量如终端用户/父进程/负荷调节的需要 强制使进程放弃处理机而转入的状态)

 

 

PCB进程标识符处理机状态进程调度信息进程控制信息
说明:内部标识符(数字)是由处理机的各种寄存器中的内容组成 的与进程调度和进程对换有关的信息程序段/数据段地址..
外部标识符(由创建者提供)进程状态/进程优先级..

进程控制

原语

操作系统提供各种进程控制原语。用户可以使用原语实现各种操作。原语也称为原子操作。

两个层级

  1. 指令级:该指令(原语)在执行期间不能中断,务必保证指令执行的完整性

  2. 功能级(函数):作为原语的程序段不允许并发执行—保证原语执行的完整性

原语常驻内存,只能在核心态运行。

进程控制原语:

  1. 创建原语

  2. 撤销原语

  3. 阻塞原语

  4. 唤醒原语

  5. 挂起原语

  6. 激活原语

进程创建

进程创建可以以系统调用(操作系统编程接口)的方式调用进程创建原语

一个进程可以创建另外一个进程。子进程也可以创建其子进程。由PCB中的ppidcpid的数据项用来保存父子进程的信息。

子进程被创建时继承父进程的所有资源:创建一个子进程,在进程管理上,实际上是为子进程分配一个PCB,会在内存中为子进程开辟内存,将父进程的代码和数据copy到子进程的内存中。子进程可以具有自己的执行程序。

继承创建过程:

  1. 申请空白PCB

  2. 分配必要的空间资源(资源分配)

  3. 初始化PCB

  4. 将创建的进程加入就绪队列,等待CPU

父子进程的与运行方式:

  1. 父进程和子进程并发执行

  2. 当创建子进程之后,父进程阻塞,等待它创建的子进程执行完毕后执行

进程的终止

引发进程终止的事件:

  1. 正常结束

  2. 越界错误

  3. 保护错(进程访问不允许访问的文件)

  4. 非法指令(试图调用不存在的指令)

  5. 特权指令错(试图调用OS执行的指令)

  6. 运行超时

  7. 等待超时

  8. 算是运算错

  9. I/O故障

  10. 外界干预(用户、父进程请求、父进程终止{不一定})

终止的过程:

  1. 访问PCB读取进程当前运行的状态

  2. 若执行中,则终止进程的执行

  3. 若存在子进程,将其所有的子进程终止,防止子进程失控

  4. 释放进程所有资源

  5. 将其PCB从所在的队列移除

阻塞/唤醒

引起进程阻塞和唤醒的事件:

  1. 请求系统服务

  2. 启动某种操作

  3. 新数据尚未到达

  4. 无新工作可做

阻塞过程:

  1. 进程停止执行

  2. 保护现场PCB信息

  3. 改变状态

  4. 将PCB挂在阻塞队列中

唤醒过程:

  1. 唤醒条件出现,产生中断

  2. 从阻塞队列中移除该PCB

  3. 将PCB放入就绪队列

挂起/激活

进程同步

异步关系:以进程为例,进程之间没有制约关系,可以任意并发执行,称这些进程之间是异步关系。

同步关系:进程之间存在制约关系,进程不能以任意方式并发执行,必须按照制约要求在特定带你顺序执行,称这些进程具有同步关系

信号量机制:类似于信号灯的数据结构,用来保证进程间能按照规定顺序执行。

分类:

  1. 同步:进程之间的协作关系。

  2. 互斥:竞争访问临界资源,由于竞争,所以进程只能以顺序的方式访问资源

临界资源(独占资源):在某段时间内只允许一个进程使用的资源

临界区:使用临界资源的代码段。

信号量机制

使用软件的方式实现进程同步和互斥:

两个或多个进程可以通过简单的信号进行合作,一个进程可以被迫在某一位置停止,直到它接收到一个特定的信号

任何复杂的合作需求都可以通过适当的信号结构得到满足

为通过信号量s传送资源释放信号,进程可以执行Signal(s)原语

为通过信号量s申请资源使用请求,进程可以执行Wait(s)原语

信号量通常是一个具有整数值的变量,在它之上定义三个操作(部分是原语):

  1. 初始化。(根据系统中的资源进行对信号量的初始化)

  2. wait操作/P操作:原语

    1. 信号量--;是进程申请资源的过程

    2. 若值为负数,则执行wait操作的进程被阻塞。否则进程继续执行

  3. signal操作/V操作:原语

    1. 信号量++;是进程释放资源的过程

    2. 若值小于等于零,则被wait操作阻塞的进程被解除阻塞。

struct semaphore
{
    int count;
    queueType queue;
}
void wait(semaphore s)
{
    s.count --;
    if(s.count < 0)
    {
        // 将当前进程阻塞
        // 将当前进程插入到等待队列
    }
}
void signal(semaphore s)
{
    s.count ++;
    if(s.count <= 0)
    {
        // 在等待队列中选择一个进程P(也可能是在等待队列中进程相互竞争的过程)
        // 将进程P加入到就绪队列中
    }
}

经典问题

生产者-消费者问题

一组生产者进程向一组消费者进程提供产品,两类进程共享一个由n个缓冲区组成的有界缓冲池,生产者进程向空缓冲池中投放产品,消费者进程从放有数据的缓冲池中取得产品并消费掉。 只要缓冲池未满,生产者进程就可以把产品送入缓冲池;只要缓冲池未空,消费者进程便可以从缓冲池中取走产品。 但禁止生产者进程向满的缓冲池再输送产品,也禁止消费者进程从空的缓冲池中提取产品。为了防止对缓冲池重复操作,故规定在任何时候,只有一个主体可以访问缓冲池。

循环缓冲结构:

输入指针变量in指向下一个可存放产品的空缓冲区

输出指针变量out指向下一个可从中获取产品的满缓冲区

生产者放入物品:in = (in + 1) % n

消费者提取物品:out = (out + 1) % n

当 in = out 缓冲池为空

当 (in + 1) % n = out 缓冲池满

信号量的设计:

  1. 同步信号量:

empty = n // 显示当前缓冲池的可用空间 -> 生产者

full = 0 // 溴铵是当前缓冲池中物品的数量 -> 消费者

  1. 互斥信号量:

mutex = 1 // 缓冲池 生产者消费者互斥使用

Object buffer[n]; // buffer pool
int in = 0, out = 0;
struct semaphore{
    int mutex = 1;
    int empty = n;
    int full = 0;
}
void producer(){
    while(1)
    {
        wait(empty);
        wait(mutex);
        buffer[in] = p;
        in = (in + 1) % n;
        signal(mutex);
        signal(full);
    }
}
void consumer()
{
    while(1)
    {
        wait(full);
        wait(mutex);
        object = buller[out];
        out = (out + 1) % n;
        signal(muetx);
        signal(empty);
    }
}

注:在wait操作时,不能先对互斥信号量进行wait操作,否则会引起死锁现象的发生。

哲学家进餐

有5位哲学家倾注毕生精力用于思考和吃饭, 他们围坐在一张圆桌旁,在圆桌上有5个碗和5支筷子。每位哲学家的行为通常是思考,当其感到饥饿时,便试图取其左右最靠近他的筷子进餐。只有他拿到两支筷子后才能进餐,进餐完毕后,释放两支筷子并继续思考

对于筷子来说是互斥资源,为了防止思索地产生:

  1. 至多只允许有4位哲学家同时进餐,这样就能保证至少有一个哲学家能拿到两支筷子。

  2. 仅当哲学家左、右两支筷子可用时,才允许他拿起筷子进餐。

  3. 规定奇数号哲学家先拿他左边的筷子,然后再去拿右边的筷子;而偶数号哲学家则相反。 最后总会有一位哲学家能获得两支筷子而进餐

struct semaphore{
    int chopstick[5]; // 筷子的互斥资源
    int limit = 4; // 最多允许4名学家进餐
}
void philosopher(int i)
{
    while(1)
    {
        thinking();
        wait(limit); // 对人数的限制
        wait(chopstick[i]); // 左侧筷子临界访问
        wait(chopstick[(i + 1) % 5]); // 右侧筷子 同时满足
        eating();
        signal(limit);
        signal(chopstick[i]);
        signal(chopstick[(i + 1) % 5]);
    }
}

读者写者问题

多个进程间共享一个数据文件,把只要求读文件的进程称为Reader进程,其它的进程称为Writer进程。允 许多个Reader进程同时读取共享文件,但不允许一个 Writer进程和其他Reader进程或Writer进程同时访问共享对象

struct semaphore{
    int wmutex = 1;// 互斥信号量,用于区别读者和写者两种状态
    int rmutex = 1;
}
int readcount = 0;// 读者数量
void Reader(){
    while(1)
    {
        wait(rmutex);// rmutex 用于互斥修改readcount值的互斥信号量
        if(readcount == 0)
            wait(wmetux); // 当readcount == 0时,要看一下有没有wmetux的访问,如果有 Reader阻塞
        readcount ++;
        signal(rmutex);
        reading();
        wait(rmetux); // 互斥对readcount的修改
        readcount --;
        signal(rmutex);
        if(readcount == 0)
            signal(wmutex);
    }
}
void Wirter()
{
    while(1)
    {
        wait(wmutex);
        writing();
        signal(wmutex);
    }
}

00

进程通信

进程通信:进程之间的信息交换。其所交换的信息量少则一个状态或数值,多则成千上万个字节!

信号量机制作为同步工具是卓有成效的,但是作为进程通信工具还不够理想,主要表现在:

  1. 效率低

  2. 通信对用户不透明。用户干预太多 (不透明意味着用户对于处理的每一个细节都是可见的, 需要用户编程处理或干预)

类型:

  1. 共享存储器系统

  2. 消息传递系统(广泛)

  3. 管道通信系统

管道通讯

管道:⭐是指用于连接一个读进程和一个写进程 以实现他们之间通信的一个共享文件 向管道(共享文件)提供输入的发送进程(即写进程), 以字符流形式将大量的数据送入管道;而接受管道输出的接收进程(即读进程),则从管道中接收(读)数据。

管道机制协调能力:

  1. 互斥:当一个进程正在对pipe执行读/写操作时,其它(另一)进程必须等待—单工通信

  2. 同步:当写(输入)进程把一定数量(如4 KB)的数据写入pipe,便去睡眠等待,直到读(输出)进程取走数据后,再把他唤醒。当读进程读一空pipe时,也应睡眠等待,直至写进程将数据写入管道后,才将之唤醒

  3. 确定对方是否存在,只有确定了对方已存在时,才能进行通信。

消息传递通讯实现方式

直接通信方式:

发送进程和接收进程都以显式方式提供对方的标识符。

系统提供下述两条通信命令(原语):

  1. Send(Receiver, message); 发送一个消息给接收进程;

  2. Receive(Sender, message); 接收Sender发来的消息;

间接通信方式:

进程之间通过某种中间实体(信箱)进行通讯

一个进程可以将消息发送给信箱,另外一个进程从信箱获得属于它的消息

进程同步方式:

  1. 发送进程阻塞、 接收进程阻塞

  2. 发送进程不阻塞、 接收进程阻塞(应用最广的进程同步方式

  3. 发送进程和接收进程均不阻塞

消息缓冲队列通信机制

消息缓冲区:在消息缓冲队列通信方式中,主要利用的数 据结构是消息缓冲区。

PCB中有关通信的数据项:消息队列进行操作和实现同 步的信号量

线程

引入

进程的角色:

  1. 资源分配的基本单位

  2. 调度的基本单位---调度其实也是分配资源

  3. 独立运行的基本单位---独立运行的实体

进程拥有资源这一特点,使得进程的“体量”可 能很大,这使得在进行进程调度的时候,有较大的时空开销。切换的开销将限制系统并发程度的提高

若将进程的的两个属性分开,由操作系统分开处理:使得一部分运行实体,作为调度和分派的基本单位,但不拥有资源,以做到“轻装上阵”

而对于拥有资源的基本单位—进程,又不对之进行频繁的切换。进而形成了线程的概念

基本概念

线程模型里面,进程一方面可以克隆自己,创建一个子进程与其并发执行。另一方面,进程可以把自己代码的一部分(例如代码中某个函 数)创建(不是克隆)一些迷你执行体(线程),让迷你执行体与自己并发执行。

这种迷你执行体,不拥有资源,共享创建它的进程的资源,称之为线程。

线程是系统中轻量化的运行实体,它仅仅拥有ID信息、处理机状态和调度相关的状态信息等少量信息

因此,在线程模型里面,进程和线程都是执行体,两种执行体并发执行(混合并发执行)

一个进程可以创建自己的线程,这些线程共享进程的资源(进程地址空间,数据、代码和其它资源)

属性:

  1. 同一进程下的线程,共享该进程资源(一个进程的所有线程都具有相同的地址空间

  2. 轻型运行实体

  3. 独立调度和分派的基本单位。

  4. 可并发执行

线程的状态

  1. 状态参数:线程标识符和一组状态参数进行᧿述

  2. 线程运行状态:执行状态、就绪状态、阻塞状态

线程的创建:

在创建新线程时,需要利用一个线程创建函数(或系统调用),并提供相应的参数:

  1. 指向线程主程序的入口指针(线程要执行的函数地址

  2. 堆栈的大小

  3. 用于调度的优先级等

在线程创建函数执行完后,将返回一个线程标识符供以后使用。

线程间的同步和通信

互斥锁mutex

可用两条命令(函数)对互斥锁进行操作:

  1. lock 关锁 (wait

  2. unlock 开锁 (signal

条件变量 Solaris

每一个条件变量必须与一个互斥锁一起使用,亦即,在创建一个互斥锁时便联系着一个条件变量

信号量机制

  1. 私用信号量(同一进程中各线程间的同步

  2. 公用信号量(实现不同进程中各线程之间的同步

线程的实现

线程的实现分成三类:

  1. 内核支持线程

  2. 用户级线程

  3. 混合支持线程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值