IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> 操作系统——信号量的实现与使用 -> 正文阅读

[系统运维]操作系统——信号量的实现与使用

目录

前言

一、信号量的使用

二、信号量的实现

1.有正有负信号量的实现

2.只有正数的信号量的实现



前言

在上一篇文章中,我们介绍了临界区的概念,并用临界区实现了对信号量的保护,使信号量能够拥有正确的语义,通过信号量的数值表达的语义进行操作就可以实现对进程的阻塞和唤醒。操作系统给上层用户提供了信号量定义接口和P、V操作接口后,用户就可以调用这些接口完成进程同步


一、信号量的使用

根据信号量的含义:

1.信号量是一个需要被多个进程共享的整数;

2.根据信号量的值让相应的值睡眠或唤醒,操作的对象是进程PCB;

3.在操作信号量时需要进行临界区保护,用Lamport面包店算法或开关中断操作等。

应当将信号量的实现放在操作系统内核中,并且将信号量的P、V操作定义为系统调用,这是因为将一个变量放在操作系统内核中所有进程,并且在系统中对PCB进行操作、实现开关中断也比较方便。

一般信号量实现为系统内核中的数据对象,而P、V操作实现为系统提供给上层用户程序的两个系统调用。

POSIX标准定义了四个基本系统调用:

sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);

?这个系统调用用来打开或创建一个信号量变量,name是信号量的名字,oflag选择创建一个新的信号量或者打开一个现有的信号量,mode是权限位,value是信号量的初值。

int sem_unlink(count char* name);

根据名字从系统中删除信号量。

int sem_wait(sem_t* sem);
int sem_post(sem_t* sem);

对应信号量的V操作和P操作。

现在编写一个应用程序来模拟经典的生产者——消费者问题:

1.创建一个生产者进程和五个消费者进程;

2.通过操作同一个文件来建立一个共享数据缓存区;

3.生产者依次向缓存区文件写入0,1,2,···,499五百个整数;

4.每个消费者进程从缓存区中读取100个数,每读出一个数就打印到标准输出上;

5.缓存区最多保存10个数。

main()
{
    if(!fork())//生产者进程
    {
        empty = sem_open("empty", 10);//只输入了名字和初值
        full = sem_open("full", 0);
        mutex = sem_open("mutex", 1);
        for(i = 0; i < 500; i++)
        {
            sem_wait(empty);
            sem_wait(mutex);
            读写文件的操作;
            sem_post(mutex);
            sem_post(full);
        }
    }
    
    if(!fork())//消费者进程
    {
         empty = sem_open("empty", 10);
         ......//类似内容
    }
}

二、信号量的实现

1.有正有负信号量的实现

核心问题是P、V这两个系统调用的实现,这两个系统调用的核心是对系统内核中的一个整型变量进行操作,并根据变量的数值决定是否对进程进行唤醒或阻塞。

sys_sem_wait(sem_t *sem)
{
    cli();//进入区代码,可以是Lamport面包店算法或者硬件原子指令法等;
    sem->value--;
    if((sem->value) < 0)
    {
        current->state = SLEEP;//将当前进程阻塞;
        将当前进程追加到sem->queue队列的尾部;
        schedule;//切换到别的进程
    }
    sti();//退出区代码
}

sys_sem_post(sem_t *sem)
{
    cli();//进入区代码
    sem->value++;
    if((sem->value) >= 0)
    {
        从sem->queue队列首部取出一个进程;
        current->state = READY;
        将该进程加入到就绪队列中;
    }
    sti();
}
        

2.只有正数的信号量的实现

上述的有正有负的信号量,正值表示的是当前拥有的资源数量,当信号量增加1,那么就会唤醒一个阻塞队列中的进程,那么应当是哪个进程被唤醒了?

如果按照顺序,首先唤醒队列头部的进程,就可能出现高优先级的进程一直无法被唤醒,反而处于队列前面的低优先级进程先被唤醒。

为了避免这一情况的出现,当sem_post决定唤醒队列中的进程时,先将阻塞在信号量上的所有进程都唤醒,由CPU调度算法schedule()来决定由哪个进程获得信号量。所有被唤醒的进程都需要检测自己是否获得了信号量,没有获得信号量的继续阻塞状态。

sys_sem_wait(sem_t *sem)
{
    cli();//进入区代码,可以是Lamport面包店算法或者硬件原子指令法等;
    while((sem->value) = 0)
    {
        将当前进程追加到sem->queue队列的尾部;
        schedule;//切换到别的进程
    }
     sem->value--;
    sti();//退出区代码
}

sys_sem_post(sem_t *sem)
{
    cli();//进入区代码
    sem->value++;
    让sem->queue队列中的所有进程都加入就绪队列;
    sti();
}
        

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2021-08-31 15:52:22  更:2021-08-31 15:54:14 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 11:41:40-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码