首页 > 系统相关 >linux进程间通信——信号量(通俗易懂,看这一篇就够了)

linux进程间通信——信号量(通俗易懂,看这一篇就够了)

时间:2024-09-02 22:14:15浏览次数:8  
标签:信号量 struct IPC int semid 就够 间通信 value

信号量

概念

特点

  • 信号量实际是一个计数器。信号量用于实现进程间的互斥与同步,而不是用于存储 进程间通信 数据。很多进程会访问同一资源,或者向共享内存写入一些东西,为防止争夺资源混乱。可以给一些进程上锁,让其排队等待

工作原理

  1. P(sv):如果sv的值大于零,就给它减1;如果它的值为零,就挂起该进程的执行
  2. V(sv):如果有其他进程因等待sv而被挂起,就让它恢复运行,如果没有进程因等待sv而挂起,就给它加1.

在信号量进行PV操作时都为原子操作(因为它需要保护临界资源)

注:原子操作:单指令的操作称为原子的,单条指令的执行是不会被打断的

步骤:

  1. 创建或者使用信号灯集
  2. 对某信号灯做PV操作(P减法,V加法)
  3. 删除信号灯集(非必须)

创建/获取信号量集

semphore get

功能

  • 创建一个新信号量或获取一个已有信号量

函数原型

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);
  • key:唯一非零的整数值(和共享内存中的参数定义一致,key不变可以获取相同的信号灯集)
    • IPC_PRIVATE
    • ftok()
  • nsems:创建的信号量的个数(PV操作的钥匙个数)
  • semflg:一组标志
    • IPC_CREAT | 0666:当信号量不存在时创建一个新的信号量,并指定权限
    • IPC_CREAT | IPC_EXCL | 0666:创建一个新的,唯一的信号量,如果信号量已存在,返回一个错误。

返回值

  • 成功返回一个相应信号量集的标识号(非负整数)
  • 失败返回-1,并设置 errno

注意事项

  • nsems当前信号集中的信号量的个数,不是value值,semid是用于标识这一组信号量(即标识信号量集)

  • 示例:

    semget(key, 2, IPC_CREAT | 0666);
    
    • 创建一个信号量集,里面包含两个信号量,一个下标为0,另一个下标为1
    • 初始的value值都为0(没有通过semctl()修改),所以一旦先执行P操作,就会阻塞。

semget error: Invalid argument

  • 原因:semget之前创建的信号量集未删除(即nsms不一致)

    image-20240902214210359

    image-20240902214248861

  • 解决:使用命令ipcrm -s semid(semid为具体的信号量集标识符)删除系统中的信号量集,重新创建

使用命令查看信号量

ipcs -s # # interprocess communication status——进程间通信的状态 s——semaphore  
image-20240902095853401

PV操作

功能

  • 对某些信号量做 P(减法)和 V(加法)操作

函数原型

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

int semop(int semid, struct sembuf *sops, size_t nsops);
  • semid:信号量集标识号,semget()的返回值

  • sops:一个指向struct sembuf类型的指针

    struct sembuf
    {
        unsigned short int sem_num;	// 信号量组中对应的序号,0~sem_nums-1
        short int sem_op;	 		// 信号量值在一次操作中的改变量 +5(V操作) -5(P操作)
        short int sem_flg;			/* operation flag */
    };
    
    • sem_flg:0 阻塞 IPC_NOWAIT 不阻塞
  • nsops:操作的信号灯个数

返回值

  • 成功返回0
  • 失败返回-1,并设置 errno

示例1

struct sembuf ss1 = {0, -1, 0};
struct sembuf ss1 = {-1, -2, 0};
struct sembuf arr[2] = {ss1, ss2};
semop(semid, arr, 2); // semid为具体的信号灯标识号

示例2

struct sembuf ss = {0, -5, 0};
semop(semid, &ss, 1);

删除信号量集

功能

  • 对信号量集进行控制

函数原型

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

int semctl(int semid, int semnum, int cmd, ...);
  • semid:信号量集的标识号

  • semnum:信号量集中的某个信号量的下标

  • cmd

    • SETVAL:设置某个信号量的 value 值(这个值通过union semun中的val成员设置)

      • union semum结构体

        union semun {
            int              val;    /* 用于 SETVAL 的值 */
            struct semid_ds *buf;    /* 用于 IPC_STAT、IPC_SET 的缓冲区 */
            unsigned short  *array;  /* 用于 GETALL、SETALL 的数组 */
            struct seminfo  *__buf;  /* 用于 IPC_INFO(Linux 特定)的缓冲区 */
        };
        
      • 示例:

        union semun us;
        us.val = 5;
        semctl(semid, 0, SETVAL, us, NULL); // 并没有要求必须以NULL结尾
        
    • GETVAL:获取到 某个信号量的 value 值

      • 示例:

        semctl(semid, 0, GETVAL, NULL);
        
    • IPC_RMID:删除整个信号量集,不需要缺省参数,只需要三个参数即可

      • 示例:

        semctl(semid, 0, IPC_RMID, NULL);
        

返回值

  • 成功,根据cmd返回一个非负值
    • 对于SETVALGETVALIPC_RMID返回0代表成功
  • 失败,返回-1,并设置errno

linux union semun报错storage size isn‘t known

  • 原因:内核中的union sem_union联合体被注释

  • 解决:自己实现

    #if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)
    /* union semun is defined by including <sys/sem.h> */
    #else
    /* according to X/OPEN we have to define it ourselves */
    union semun
    {
        int              val;   /* value for SETVAL */
        struct semid_ds* buf;   /* buffer for IPC_STAT, IPC_SET */
        unsigned short*  array; /* array for GETALL, SETALL */
        /* Linux specific part: */
        struct seminfo* __buf; /* buffer for IPC_INFO */
    };
    #endif
    

使用命令删除信号量集

ipcrm -s # interprocess communication remove	s——semphore

综合示例

semget_p

概述:

  1. 通过调用ftok函数,创建唯一键值
  2. 创建/返回信号量集(初始时value为0)
  3. 修改value值为5
  4. 执行p操作,需要value值为6,不够,故阻塞
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>

#if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)
/* union semun is defined by including <sys/sem.h> */
#else
/* according to X/OPEN we have to define it ourselves */
union semun
{
    int              val;   /* value for SETVAL */
    struct semid_ds* buf;   /* buffer for IPC_STAT, IPC_SET */
    unsigned short*  array; /* array for GETALL, SETALL */
    /* Linux specific part: */
    struct seminfo* __buf; /* buffer for IPC_INFO */
};
#endif

int main(int argc, char* argv[])
{
    key_t          key;
    int            semid;
    struct sembuf* sops;
    int            ret;

    // 创建key
    if (-1 == (key = ftok("../ftok.txt", 7)))
    {
        perror("ftok error");
        exit(-1);
    }
    printf("key:%#x\n", key);

    // 创建信号量集,当前集合中有3个信号量,下标分别为012,初始value为0
    if (-1 == (semid = semget(key, 3, IPC_CREAT | 0666)))
    {
        perror("semget error");
        exit(-1);
    }
    printf("semid:%d\n", semid);

    // V操作, 下标0,增加1个value值,0表示阻塞
    struct sembuf ss = {0, 1, 0};
    if (-1 == (ret = semop(semid, &ss, 1)))
    {
        perror("semop error");
        exit(-1);
    }
    printf("I am back--v\n");

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

    return 0;
}

semget_v

概述:

  1. 通过调用ftok函数,创建唯一键值
  2. 创建/返回信号量集(初始时value为0)
  3. 修改value值为5(二次修改,会立即生效,即使此时P操作还在阻塞)
    • 如果直接修改value值为6,此时P操作(需要value值为5)会立刻结束阻塞
  4. 执行V操作,释放一个value值,P操作结束阻塞
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>

#if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)
/* union semun is defined by including <sys/sem.h> */
#else
/* according to X/OPEN we have to define it ourselves */
union semun
{
    int              val;   /* value for SETVAL */
    struct semid_ds* buf;   /* buffer for IPC_STAT, IPC_SET */
    unsigned short*  array; /* array for GETALL, SETALL */
    /* Linux specific part: */
    struct seminfo* __buf; /* buffer for IPC_INFO */
};
#endif

int main(int argc, char* argv[])
{
    key_t          key;
    int            semid;
    struct sembuf* sops;
    int            ret;
    union semun    us;

    // 创建key
    if (-1 == (key = ftok("../ftok.txt", 7)))
    {
        perror("ftok error");
        exit(-1);
    }
    printf("key:%#x\n", key);

    // 创建信号量集,当前集合中有3个信号量,下标分别为012,初始value为0
    if (-1 == (semid = semget(key, 3, IPC_CREAT | 0666)))
    {
        perror("semget error");
        exit(-1);
    }
    printf("semid:%d\n", semid);

    // 修改信号量的value值(修改后,会立即剩下,即使p操作还在阻塞状态)
    us.val = 5;
    // 并没有要求必须以NULL结尾
    if (0 != semctl(semid, 0, SETVAL, us, NULL))
    {
        perror("semctl error");
        exit(-1);
    }

    // V操作, 下标0,增加1个value值,0表示阻塞
    struct sembuf ss = {0, 1, 0};
    if (-1 == (ret = semop(semid, &ss, 1)))
    {
        perror("semop error");
        exit(-1);
    }
    printf("I am back--v\n");

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

    return 0;
}

标签:信号量,struct,IPC,int,semid,就够,间通信,value
From: https://www.cnblogs.com/General-xd/p/18393653

相关文章

  • 大模型LLM学习路线图2024年最新版!全面掌握学习路径,非常详细,想学大模型收藏这一篇就够
    ChatGPT的出现在全球掀起了AI大模型的浪潮,2023年可以被称为AI元年,AI大模型以一种野蛮的方式,闯入你我的生活之中。从问答对话到辅助编程,从图画解析到自主创作,AI所展现出来的能力,超出了多数人的预料,让不少人惊呼:“未来是属于AI的”。AI大模型——成为互联网从业者必备技能。......
  • 大模型LLM学习路线图2024年最新版!全面掌握学习路径,非常详细,想学大模型收藏这一篇就够
    ChatGPT的出现在全球掀起了AI大模型的浪潮,2023年可以被称为AI元年,AI大模型以一种野蛮的方式,闯入你我的生活之中。从问答对话到辅助编程,从图画解析到自主创作,AI所展现出来的能力,超出了多数人的预料,让不少人惊呼:“未来是属于AI的”。AI大模型——成为互联网从业者必备技能。......
  • 大模型应用,这些书不能错过!大模型入门到精通,非常详细收藏我这一篇就够了
    在这个信息爆炸的时代,人工智能正以前所未有的速度和规模渗透到我们生活的方方面面。其中,大模型应用作为AI领域的一大亮点,不仅在学术界引起广泛关注,更在工业界展现出巨大的应用潜力。从自然语言处理到图像识别,从数据分析到智能推荐,大模型以其强大的学习能力和泛化能力,不断......
  • 测试小白入门-03测试理论知识看这一篇就够了
    文章目录前言一、软件开发过程模型瀑布开发模型(熟悉)快速原型模型(理解)螺旋模型(了解)二、测试模型测试V模型(代表性)测试W模型(中大型企业)测试H模型(了解)三、测试方法分类是否覆盖源代码是否运行是否覆盖源代码是否自动化其他四、编写测试用例的方法1.等价划分类2.边界值3.......
  • IO进程day06(进程间通信、信号、共享内存)
    目录【1】进程间通信IPC1》进程间通信方式2》无名管道1>特点2>函数接口3>注意事项练习:父子进程实现通信,父进程循环从终端输入数据,子进程循环打印数据,当输入quit结束。3》有名管道 1>特点2>函数接口3>注意事项 练习:通过两个进程实现cp功能 4>有名管......
  • SSM框架学习!~~~一篇文章就够了!
    详细解释SSM框架SSM框架是Spring、SpringMVC和MyBatis框架的整合,它遵循标准的MVC(Model-View-Controller)设计模式,旨在提高JavaWeb开发的效率和可维护性。下面将详细解释SSM框架的各个组成部分及其作用。Spring框架概述:Spring框架是一个开源的、全面的企业级应用开发框......
  • 怎么入门网络安全,学这两类证书就够了NISP或CISP_cisp和nisp2级题库一样吗
    其实网络安全这个门槛,对于当代的年轻人来说,不高也不低。其中NISP证书分为一级、二级、三级(专项),证书由中国信息安全测评中心颁发,持NISP二级证书可与免考兑换CISP证书。因为CISP报考需要工作经验,NISP填补了在校大学生无法考取CISP证书的空白,被称为“校园版CISP”。看到上一......
  • 保姆级 Stable Diffusion 教程(附整合包),看完这篇就够了!
    2022年8月,在美国科罗拉多州举办了一场新兴数字艺术家竞赛,一幅名为《太空歌剧院》的作品获得“数字艺术/数字修饰照片”类别的一等奖,神奇的是,该作品的作者并没有绘画基础,这幅画是他用AI生成的。这一事件展示了AI在绘画领域惊人的创造力,让人们见识到,AI作品不仅可以......
  • 进程间通信----管道篇
    目录一丶  无名管道1. 特点2. 读写特性3. 函数接口二丶有名管道1.特点:2.函数接口3.读写特性一丶  无名管道1. 特点        1. 只能用于具有亲缘关系的进程之间的通信        2. 半双工的通信模式,具有固定的读端和写端   ......
  • SolidJS-多文件间传递同一个信号量
    SolidJS-多文件间传递同一个信号量现在我在controlPanel.tsx中返回了一个控制面板(HTML代码),可以控制node、link、step1和step2的值。在matrixWave.tsx中我根据node、link、step1和step2的值进行数据的过滤,然后生成对应的matrixWave的SVG图。因此,我希望在web中对node、link、step1......