信号灯集,消息队列

news2025/7/19 15:39:37

信号灯集

1、概念

信号灯(semaphore),也叫信号量。它是不同进程间或一个给定进程内部不同线程间同步的机制;System V的信号灯是一个或者多个信号灯的一个集合。其中的每一个都是单独的计数信号灯。而Posix信号灯指的是单个计数信号灯。

通过信号灯集实现共享内存的同步操作。

  1. 步骤

在不同的进程间,通过相同的key值,打开相同的信号灯集

  1. 创建key值 ftok
  2. 创建或打开信号灯集semget
  3. 初始化信号灯 semctl
  4. PV操作 semop
  5. 删除信号灯集 semctl
  1. 函数

1)semget 创建\打开信号灯

int semget(key_t key, int nsems, int semflg);
功能:创建/打开信号灯
参数:key:ftok产生的key值
    nsems:信号灯集中包含的信号灯数目
    semflg:信号灯集的访问权限,通常为IPC_CREAT |IPC_EXCL |0666
返回值:成功:信号灯集ID
       失败:-1

2)semctl 信号灯集合的控制(初始化/删除)

int semctl ( int semid, int semnum,  int cmd…/*union semun arg*/);
功能:信号灯集合的控制(初始化/删除)
参数:semid:信号灯集ID
    semnum: 要操作的集合中的信号灯编号
     cmd:
        GETVAL:获取信号灯的值,返回值是获得值
        SETVAL:设置信号灯的值,需要用到第四个参数:共用体
        IPC_RMID:从系统中删除信号灯集合
返回值:成功 0
      失败 -1
用法:初始化:
union semun{
    int val;
}mysemun;
mysemun.val = 10;
semctl(semid, 0, SETVAL, mysemun);
获取信号灯值:函数semctl(semid, 0, GETVAL)的返回值
删除信号灯集:semctl(semid, 0, IPC_RMID);

3)semop 对信号灯集合中的信号量进行PV操作

int semop ( int semid, struct sembuf  *opsptr,  size_t  nops);
功能:对信号灯集合中的信号量进行PV操作
参数:semid:信号灯集ID
     opsptr:操作方式
     nops:  要操作的信号灯的个数 1
返回值:成功 :0
      失败:-1
struct sembuf {
   short  sem_num; // 要操作的信号灯的编号
   short  sem_op;  //    0 :  等待,直到信号灯的值变成0
                   //   1  :  释放资源,V操作
                   //   -1 :  申请资源,P操作                    
    short  sem_flg; // 0(阻塞),IPC_NOWAIT, SEM_UNDO
};
用法:
申请资源 P操作:
    mysembuf.sem_num = 0;
    mysembuf.sem_op = -1;
    mysembuf.sem_flg = 0;
    semop(semid, &mysembuf, 1);
释放资源 V操作:
    mysembuf.sem_num = 0;
    mysembuf.sem_op = 1;
    mysembuf.sem_flg = 0;
    semop(semid, &mysembuf, 1);

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

union semun {
    int val;
};

int main(int argc, char const *argv[])
{
    //1.创建key值
    key_t key = ftok(".", 'x');
    if (key < 0)
    {
        perror("ftok err");
        return -1;
    }
    printf("key:%d\n", key);
    //2.创建或打开信号灯集
    int semid = semget(key, 2, IPC_CREAT | IPC_EXCL | 0666); //创建
    if (semid <= 0)                                          //创建失败
    {
        if (errno == 17)
            semid = semget(key, 2, 0666); //打开
        else
        {
            perror("semget err");
            return -1;
        }
    }
    else //创建成功-->初始化
    {
        //初始化
        //创建初始化
        union semun sem;
        sem.val = 0;
        semctl(semid, 0, SETVAL, sem); //0号灯初值0
        sem.val = 10;
        semctl(semid, 1, SETVAL, sem); //1号灯初值10
    }
    printf("semid:%d\n", semid);

    printf("%d\n", semctl(semid, 0, GETVAL));
    printf("%d\n", semctl(semid, 1, GETVAL));

    //PV操作
    struct sembuf buf;
    // 操作0号灯
    buf.sem_num = 0; //信号灯得编号
    buf.sem_op = 1;  //释放资源 : +1
    buf.sem_flg = 0;
    //1:操作1个灯
    semop(semid, &buf, 1);
    printf("%d\n", semctl(semid, 0, GETVAL));

    //操作1号灯
    buf.sem_num = 1; //信号灯得编号
    buf.sem_op = -1; //申请资源:-1
    buf.sem_flg = 0; //当信号灯得资源为0时,申请不到资源,阻塞
    //IPC_NOWAIT:到0不阻塞
    //1:操作一个灯
    semop(semid, &buf, 1);
    printf("%d\n", semctl(semid, 1, GETVAL));

    //删除信号灯集
    semctl(semid, 0, IPC_RMID);

    return 0;
}

  1. 命令查看灯集

ipcs -s:查看信号灯集

ipcrm -s semid:删除信号灯集

  1. 练习

两个进程实现通信,一个进程循环从终端输入,另一个进程循环打印,当输入quit时结束

共享内存+信号灯集+封装函数(自主选择)

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

union semun {
    int val;
};

int main(int argc, char const *argv[])
{
    //创建key
    key_t key = ftok(".", 'a');
    if (key < 0)
    {
        perror("ftok err");
        return -1;
    }
    printf("key:%d\n", key);
    //创建或打开共享内存
    int shmid = shmget(key, 256, IPC_CREAT | IPC_EXCL | 0666);
    if (shmid < 0)
    {
        if (errno == 17)
            shmid = shmget(key, 256, 0666);
        else
        {
            perror("shmget err");
            return -1;
        }
    }
    printf("shmid:%d\n", shmid);
    //映射
    char *= shmat(shmid, NULL, 0);
    if (== (char *)-1)
    {
        perror("shmat err");
        return -1;
    }
    //创建或打开信号灯集
    int semid = semget(key, 1, IPC_CREAT | IPC_EXCL | 0666);
    if (semid <= 0)
    {
        if (errno == 17)
            semid = semget(key, 1, 0666);
        else
        {
            perror("semget err");
            return -1;
        }
    }
    else
    {
        //初始化
        union semun sem;
        sem.val = 0;
        semctl(semid, 0, SETVAL, sem);
    }
    //写
    struct sembuf s;
    s.sem_num = 0;
    s.sem_op = 1;
    s.sem_flg = 0;
    while (1)
    {
        read(0, p, 256);
        semop(semid, &s, 1);
        if (!strcmp(p, "quit\n"))
            break;
    }
    //取消映射
    shmdt(p);

    return 0;
}

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

union semun {
    int val;
};

int main(int argc, char const *argv[])
{
    //创建key
    key_t key = ftok(".", 'a');
    if (key < 0)
    {
        perror("ftok err");
        return -1;
    }
    printf("key:%d\n", key);
    //创建或打开共享内存
    int shmid = shmget(key, 256, IPC_CREAT | IPC_EXCL | 0666);
    if (shmid < 0)
    {
        if (errno == 17)
            shmid = shmget(key, 256, 0666);
        else
        {
            perror("shmget err");
            return -1;
        }
    }
    printf("shmid:%d\n", shmid);
    //映射
    char *= shmat(shmid, NULL, 0);
    if (== (char *)-1)
    {
        perror("shmat err");
        return -1;
    }
    //创建或打开信号灯集
    int semid = semget(key, 1, IPC_CREAT | IPC_EXCL | 0666);
    if (semid <= 0)
    {
        if (errno == 17)
            semid = semget(key, 1, 0666);
        else
        {
            perror("semget err");
            return -1;
        }
    }
    else
    {
        //初始化
        union semun sem;
        sem.val = 0;
        semctl(semid, 0, SETVAL, sem);
    }
    //读
    struct sembuf s;
    s.sem_num = 0;
    s.sem_op = -1;
    s.sem_flg = 0;
    while (1)
    {
        semop(semid, &s, 1);
        if (!strcmp(p, "quit\n"))
            break;
        write(1, p, 256);
        //清空
        memset(p, 0, 256);
    }
    //取消映射
    shmdt(p);
    //删除
    shmctl(shmid, IPC_RMID, NULL);
    semctl(semid, 0, IPC_RMID);
    return 0;
}

消息队列

1、特点

消息队列是IPC对象的一种

消息队列由消息队列ID来唯一标识

消息队列就是一个消息的列表。用户可以在消息队列中添加消息、读取消息等。

消息队列可以按照类型来发送(添加)/接收(读取)消息

2.步骤

在不同的进程中,通过相同的key值,拿到相同的消息队列

  1. 创建key值 ftok
  2. 创建或打开消息队列 msgget
  3. 添加消息:按照类型将消息添加到已经打开的消息队列末尾 msgsnd
  4. 读取消息:按照类型把消息从消息队列中读走 msgrcv
  5. 删除消息队列 msgctl

3.函数

1)msgget创建或打开一个消息队列

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int flag);
功能:创建或打开一个消息队列
参数:  key值
       flag:创建消息队列的权限IPC_CREAT|IPC_EXCL|0666
返回值:成功:msgid
       失败:-1

2)msgsnd添加消息

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msqid, const void *msgp, size_t size, int flag); 
功能:添加消息
参数:msqid:消息队列的ID
      msgp:指向消息的指针。常用消息结构msgbuf如下:
          struct msgbuf
          {
            long mtype;          //消息类型
            char mtext[N]
            };   //消息正文
   size:发送的消息正文的字节数
   flag:IPC_NOWAIT消息没有发送完成函数也会立即返回    
         0:直到发送完成函数才返回
返回值:成功:0
      失败:-1
使用:msgsnd(msgid, &msg,sizeof(msg)-sizeof(long), 0)
注意:消息结构除了第一个成员必须为long类型外,其他成员可以根据应用的需求自行定义。

3)msgrcv读取消息

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgrcv(int msgid,  void* msgp,  size_t  size,  long msgtype,  int  flag);
功能:读取消息
参数:msgid:消息队列的ID
     msgp:存放读取消息的空间
     size:接受的消息正文的字节数
    msgtype:0:接收消息队列中第一个消息。
            大于0:接收消息队列中第一个类型为msgtyp的消息.
            小于0:接收消息队列中类型值不小于msgtyp的绝对值且类型值又最小的消息。
    flag:0:若无消息函数会一直阻塞
        IPC_NOWAIT:若没有消息,进程会立即返回ENOMSG
返回值:成功:接收到的消息的长度
      失败:-1

  1. msgctl对消息队列的操作,删除消息队列

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl ( int msgqid, int cmd, struct msqid_ds *buf );
功能:对消息队列的操作,删除消息队列
参数:msqid:消息队列的队列ID
     cmd:
        IPC_STAT:读取消息队列的属性,并将其保存在buf指向的缓冲区中。
        IPC_SET:设置消息队列的属性。这个值取自buf参数。
        IPC_RMID:从系统中删除消息队列。
     buf:消息队列缓冲区
返回值:成功:0
      失败:-1
用法:msgctl(msgid, IPC_RMID, NULL

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <errno.h>
#include <string.h>

struct msgbuf
{
    long mtype;
    char name[32];
    int age;
    float score;
};

int main(int argc, char const *argv[])
{
    //1、创建key值
    key_t key = ftok(".", 'a');
    if (key < 0)
    {
        perror("ftok err");
        return -1;
    }
    printf("key:%d\n", key);
    //2、创建或打开消息对列
    int msgid = msgget(key, IPC_CREAT | IPC_EXCL | 0666);
    if (msgid <= 0)
    {
        if (errno == EEXIST)
            msgid = msgget(key, 0666);
        else
        {
            perror("msgget err");
            return -1;
        }
    }
    printf("msgid:%d\n", msgid);

    //3、添加消息
    struct msgbuf msg;
    msg.mtype = 1;
    strcpy(msg.name, "daming");
    msg.age = 18;
    msg.score = 99.99;
    msgsnd(msgid, &msg, sizeof(msg) - sizeof(long), 0);

    msg.mtype = 3;
    strcpy(msg.name, "lihua");
    msg.age = 20;
    msg.score = 69.5;
    msgsnd(msgid, &msg, sizeof(msg) - sizeof(long), 0);

    //4、读取消息
    struct msgbuf msg_r;
    //0:可以匹配任意类型的消息,拿取得是消息对列得第一条消息
    msgrcv(msgid, &msg_r, sizeof(msg_r) - sizeof(long),
           0, 0);
    printf("name:%s\n", msg_r.name);
    printf("age:%d\n", msg_r.age);
    printf("score:%.2f\n", msg_r.score);

    msgrcv(msgid, &msg_r, sizeof(msg_r) - sizeof(long),
           3, 0);
    printf("name:%s\n", msg_r.name);
    printf("age:%d\n", msg_r.age);
    printf("score:%.2f\n", msg_r.score);

    //删除消息队列
    msgctl(msgid,IPC_RMID,NULL);

    return 0;
}

4.命令

ipcs -q :查看消息队列

ipcrm -q msgid :删除消息队列

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

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

相关文章

双网卡下,如何指定网卡进行通讯

背景 LabVIEW进行网络TCP网络通讯&#xff0c;通过WIFI进行数据传输。刚好工作站有两个网口&#xff0c;一个连接外网&#xff0c;一个连接无线路由器&#xff0c;然后数据节点可以连接到无线路由。但时LabVIEW默认运行的时候&#xff0c;显示的ip地址是外网的&#xff0c;那这…

主播直播美颜SDK:提升颜值的秘诀

当下&#xff0c;主播们往往依赖于主播直播美颜SDK&#xff0c;这个技术工具为他们提供了一个让自己看起来更好看的机会。本文将深入探讨主播直播美颜SDK的工作原理、应用和影响&#xff0c;揭示提升颜值的秘诀。 一、主播直播美颜SDK是什么&#xff1f; 主播直播美颜SDK是一…

【unity3D】Dropdown组件 — 如何使用下拉菜单

&#x1f497; 未来的游戏开发程序媛&#xff0c;现在的努力学习菜鸡 &#x1f4a6;本专栏是我关于游戏开发的学习笔记 &#x1f236;本篇是unity的Dropdown组件 Dropdown组件 基础知识详细介绍 基础知识 介绍&#xff1a;Unity的Dropdown组件是一种UI控件&#xff0c;用于在下…

【数据安全好书推荐】学习数据安全不知道看哪本?这篇文章助你赢在起跑线上!文末送书5本

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏:《粉丝福利》 《C语言进阶篇》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 ⛳️ 写在前面参与规则引入《数据要素安全流通》《Python数据挖掘&#xff1a;入门、进阶与实用案例分析》《数据保…

log4j 日志的简单使用

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 前言 System.out.println("这是我的测…

P1169 [ZJOI2007] 棋盘制作

Portal. 悬线法。 悬线法&#xff0c;主要用来解决最大子矩形问题&#xff0c;由王知昆在 IOI2003 国家集训队论文中提出。 所谓“最大子矩形问题”&#xff0c;就是在一个给定的矩形网格中有一些障碍点&#xff0c;要找出网格内部不包含任何障碍点&#xff0c;且边界与坐标…

大型企业如何通过低代码平台提高开发效率和降低成本?

云计算、大数据、人工智能、物联网风口之下&#xff0c;企业数字化转型如同被按下了快进键。为快速攻破转型路上的技术关&#xff0c;企业纷纷把目光投向了低代码开发平台&#xff0c;希望可以用最短的时间&#xff0c;开发出最适合企业发展的应用。 集团企业需要什么样的数字化…

高等数学啃书汇总重难点(十)重积分

方法性的一章&#xff0c;看着唬人&#xff0c;实际上定积分学得熟练&#xff0c;就可以很轻松的掌握这一章的内容&#xff0c;重点在于计算各种坐标下的二重或三重积分~ 1.几何意义 2.定义 3.性质 4.直角坐标计算二重积分 5.极坐标计算二重积分 6.三重积分 7.重积分的应用

Mac-Java开发环境安装(JDK和Maven)

JDK安装 1、访问oracle官网&#xff0c;下载jdk 点击下载链接&#xff1a;https://www.oracle.com/java/technologies/downloads/#java11-mac 选择Mac版本&#xff0c;下载dmg 打勾点击下载&#xff0c;跳转登陆&#xff0c;没有就注册&#xff0c;输入账号密码即可下载成功…

面试高频题:你如何知道HashMap正在进行扩容操作?

亲爱的小伙伴们&#xff0c;大家好&#xff01;我是小米&#xff0c;一个热爱技术分享的小编。今天&#xff0c;我们将一起来探讨一个程序员们在日常工作中常常遇到的问题——如何知道HashMap正在扩容。 HashMap&#xff0c;作为Java中最常用的数据结构之一&#xff0c;经常在…

“眶”护光明,爱尔眼科眼眶病专家团在方寸之间寻找光明密码

2023年8月&#xff0c;右眼罹患I型神经纤维瘤病的患儿孩子小豪(化名)在父亲熊勇的带领下&#xff0c;由爱尔眼科四川眼科医院孙丰源教授主刀&#xff0c;成功接受眼眶肿瘤切除术&#xff0c;保住了眼球和视力&#xff0c;这是生病10年来专家团队为其实施的第3次治疗。 据了解&a…

易知微智慧医疗:用科技守护健康

智慧医疗系统在国内处于一个快速发展的阶段&#xff0c;先进的医疗设备加上先进的计算机技术和网络科技&#xff0c;正在为医疗行业的转型升级提供支持。智慧医疗不仅可以提高医疗机构的效率和安全性&#xff0c;还可以让患者享受更高水平的服务和医疗体验。 目前&#xff0c;智…

功能测试用例,需要详细到什么程度?

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

C++类和对象中:运算符重载+const成员函数+日期类的完善

C类和对象中:运算符重载const成员函数日期类的完善 一.为什么C会有运算符重载这个语法呢?1.需求说明2.实现1.不规范的解决方案1.代码实现2.缺陷 3.具体的解决方案:运算符重载 二.运算符重载的语法形式1.语法形式2.private私有成员的解决方案1.封装出get函数,能够在类外读取对应…

小米6x 小米6x 一键刷twrp 安装面具magisk 实现root

为了在安卓上抓包chatgpt 只能root小米6x 来安装抓包工具小黄鸟 才能安装根证书来解析https。 工具面具卡包 1.一键刷TWRP 小米6X一键线recovery(需要先解bl锁)-20180506重发.zip - 蓝奏云 2. 在安装前清除数据 在开始刷机之前&#xff0c;需要先格式化 Data 分区和清除 Cac…

机械应用笔记

1. 螺纹转换头&#xff1a;又名金属塞头&#xff0c;例如M20-M16&#xff1b;适合于大小螺纹转换用&#xff1b; 2. 螺纹分英制和公制&#xff0c;攻丝同样也有英制和公制之分&#xff1b; 3. DB9头制作&#xff0c;M6.5的线&#xff0c;用M6.5的钻头扩线孔&#xff0c;在根…

onlyoffice 二次开发 连接器(connector) 表单填(Filling out the form) jsApi级别操作文档

阅读须知&#xff1a;本文针对有对word/excel进行js操作的需求 本次改造基于V7.3.3进行&#xff0c;已经更新进入docker。 小伙伴们须知&#xff1a;改造后的office docker需要付费&#xff08;875元&#xff09;&#xff0c;等于wps一个月费用 欢迎大家一起交流&#xff1a;V&…

Pandas教程(非常详细)(第一部分)

Pandas 库是一个免费、开源的第三方 Python 库&#xff0c;是 Python 数据分析必不可少的工具之一&#xff0c;它为 Python 数据分析提供了高性能&#xff0c;且易于使用的数据结构&#xff0c;即 Series 和 DataFrame。Pandas 自诞生后被应用于众多的领域&#xff0c;比如金融…

HarmonyOS鸿蒙原生应用开发设计- 元服务(原子化服务)图标

HarmonyOS设计文档中&#xff0c;为大家提供了独特的元服务图标&#xff0c;开发者可以根据需要直接引用。 开发者直接使用官方提供的元服务图标内容&#xff0c;既可以符合HarmonyOS原生应用的开发上架运营规范&#xff0c;又可以防止使用别人的元服务图标侵权意外情况等&…

echarts 实现分组和显示总数

echart 除了能显示坐标轴外&#xff0c;还可以对坐标轴进行分组&#xff0c;可以更直观的观察数 据&#xff0c;本博文记录一下关于分组的探索&#xff0c;先展示一下效果图&#xff1a; // 直接复制到echarts官方示例中查看效果 let xAxisData []; let data1 []; let data2 …