信号量SytemV与Posix信号量的介绍与用法

news2024/11/25 16:31:27

目录

1、信号量介绍

2、信号量SystemV介绍

2.1 信号量函数

2.2 信号量C++代码实现

 3、信号量Posix介绍

3.1 无名信号量

3.2 有名信号量


1、信号量介绍

信号量是一种计数器,用在多进程、多线程的共享资源访问控制上面,防止多进程、多线程对共享资源的同时读写。信号量种类有SystemV信号量和Posix信号量。

2、信号量SystemV介绍

信号量SystemV是Linux操作系统的内核对象,由内核同一管理,它的生命周期不依赖创建的进程,即使进程退出,信号量依然存在。信号量SystemV常用于多进程间的同步。最简单的信号信号量是只能取0和1的变量,也叫做二进制信号量,可以去多个正数的信号量被称为通用信号量,本文主要讲解二进制信号量。

2.1 信号量函数

头文件sem.h

(1)semget函数

/*
* @brief: 创建一个新信号量或取得一个已有的信号量。
* @param __key: 信号量标识符,值具有唯一性,不相关进程可以通过它访问一个信号量,常用16进制表示
* @param __nsems: 指定创建信号量数目,常为1,获取已有信号量时值为0.
* @param __semflg:一组标志,它由信号量的访问权限和创建标志组成。
    常用的标志:(1)0640|IPC_CREAT 创建一个新信号量,即使创建的信号量已存在也不会报错;
       (2)0640|IPC_CREAT|IPC_EXCL 创建的新信号量存在时,如果创建的信号量存在,会报错。
* @return int :成功,返回创建成功的信号量标识符;失败:返回-1,并且将errno设置为2
*/
 int semget (key_t __key, int __nsems, int __semflg)

(2)semctl函数

/*
* @brief 用来控制信号量的信息,比如信号量值设置、从系统中删除信号量
* @param __semid:semget函数返回的信号量标识符
* @param __semun:代表给该信号量集中的第几个信号量设置初始值。
* @param __cmd:  信号量操作命令,常用的命令有SETVAL、IPC_RMID
   一般cmd有以下几种:
    IPC_RMID 将信号量集从内存中删除。
    SETVAL   设置信号量集中的一个单独的信号量的值。
    IPC_STAT 读取一个信号量集的数据结构semid_ds,并将其存储在semun中的buf参数中。
    IPC_SET  设置信号量集的数据结构semid_ds中的元素ipc_perm,其值取自semun中的buf参数。
    GETALL   用于读取信号量集中的所有信号量的值。
    GETNCNT  返回正在等待资源的进程数目。
    GETPID   返回最后一个执行semop操作的进程的PID。
    GETVAL   返回信号量集中的一个单个的信号量的值。
    GETZCNT  返回这在等待完全空闲的资源的进程数目。
    SETALL   设置信号量集中的所有的信号量的值。
 @param ...:如果有第四个参数,则该参数格式通常为union semum结构,定义如下:
    union semun
    {    
        int val;    /* Value for SETVAL */通常就要它就够了
        struct semid_ds *buf;    
        unsigned short *arry;    
    };  
        赋值形式:semun.val = 1  //设置信号灯的值为1,表示有一个资源可用
    
*/
int semctl (int __semid, int __semnum, int __cmd, ...)

(3)semop函数

struct sembuf
{
  unsigned short int sem_num;	/* semaphore number */ 信号在信号集中索引,0代表第一个信号
  short int sem_op;		     /* semaphore operation */ 操作类型。 
                                P操作:sem_op = -1,
                                V操作:sem_op = 1                                                   
  short int sem_flg;		/* operation flag */ 操作标志。 通常为SEM_UNDO,使操作系统跟踪信号,                
                                          并在进程没有释放该信号量而终止时,操作系统释放信号量
};

/上面sem_op参数补充//

 sem_op > 0 信号加上 sem_op 的值,表示进程释放控制的资源;
 sem_op = 0 如果没有设置 IPC_NOWAIT,则调用进程进入睡眠状态,直到信号量的值为0;否则进程不会睡 
            眠,直接返回 EAGAIN
 sem_op < 0 信号加上 sem_op 的值。若没有设置 IPC_NOWAIT ,则调用进程阻塞,直到资源可用;否则进 
            程直接返回EAGAIN
///


/*
* @brief:用来改变信号量的值,该函数具有原子性的。
* @param __semid:由semget函数返回的信号量标识符
* @param __sops: 指向由sembuf结构表示的信号量操作数组。
* @param __nspos: 数组元素的个数
* @return int 成功返回0,失败返回-1
*/
int semop (int __semid, struct sembuf *__sops, size_t __nsops)

2.2 信号量C++代码实现

#include <iostream>
#include <string>
#include <unistd.h>
#include <errno.h>
#include <sys/ipc.h>
#include <sys/sem.h>

class Semaphore
{
private:
    union semVar
    {
        int val;
        struct semid_ds *buf;
        unsigned short *array;
    };

    int sem_id;
public:
    bool init(key_t key);
    bool wait();
    bool post();
    bool destroy();
};


bool Semaphore::init(key_t key)
{
    sem_id = semget(key,0,0640);
    if(-1 == sem_id)
    {
        if(2 == errno)
        {
            sem_id = semget(key,1,0640|IPC_CREAT);
            if(-1 == sem_id)
            {
                std::cout << "init 1 semget() error" << std::endl;
                return false;
            }else
            {
                union semVar semTmp;
                semTmp.val = 1;
                if(semctl(sem_id,0,SETVAL,semTmp) < 0)
                {
                     std::cout << "init 1 semctl() error" << std::endl;
                     return false;
                }else
                {
                    return true;
                }
            }
        }else
        {
            std::cout << "init 2 semget() error" << std::endl;
            return false;
        }
    }else
    {
        return true;
    }

}


bool Semaphore::wait(){
    struct sembuf sem_b;
    sem_b.sem_num = 0;
    sem_b.sem_op = -1;
    sem_b.sem_flg = SEM_UNDO;
    if(-1 == semop(sem_id,&sem_b,1))
    {
        std::cout << "wait semop failed." << std::endl;
        return false;
    }
    return true;
}

bool Semaphore::post()
{
    struct sembuf sem_b;
    sem_b.sem_num = 0;
    sem_b.sem_op = 1;
    sem_b.sem_flg = SEM_UNDO;
    if(-1 == semop(sem_id,&sem_b,1))
    {
        std::cout << "post semop failed." << std::endl;
        return false;
    }
    return true;
}

bool Semaphore::destroy()
{
    if(semctl(sem_id,0,IPC_RMID) == -1)
    {
        std::cout << "destroy semctl failed." << std::endl;
        return false;
    }
    return true;
}

int main()
{
    Semaphore sem;
    //初始化信号灯
    if(false == sem.init(0x5000))
    {
        std::cout << "sem init failed." << std::endl;
        return -1;
    }
    std::cout << "sem init ok." << std::endl;

    //等待信号灯挂出,等待成功后,将持有锁
    if(false == sem.wait())
    {
        std::cout << "sem wait failed." << std::endl;
        return -1;
    }
    std::cout << "sem wait ok." << std::endl;

    sleep(5);

    //挂出信号灯
    if(false == sem.post())
    {
        std::cout << "sem post failed." << std::endl;
        return -1;
    }
    std::cout << "sem post ok." << std::endl;

    //最后进程结束时,销毁信号灯
    //if(false == sem.destroy())
    //{
    //    std::cout << "sem destroy failed." << std::endl;
    //    return -1;
    //}
    //std::cout << "sem destroy ok." << std::endl;

    return 0;
}

 运行结果如下:

 3、信号量Posix介绍

Posix是“可移植操作系统接口(Portable Operating System Interface )的首字母简写,但它并不是一个单一的标准,而是一个电气与电子工程学会即IEEE开发的一系列标准,它还是由ISO(国际标准化组织)和IEC(国际电工委员会)采纳的国际标准。Posix信号分为无名信号量和有名信号量。

3.1 无名信号量

Posix的无名信号量一般用于线程同步, 无名信号量是基于用户空间内存的, 它的存续与内存的存续直接相关,无名信号量的api为:sem_init、sem_destroy。

3.2 有名信号量

Posix的有名信号量一般用于进程同步, 它也是由内核统一管理的,因此有名信号量的存续也是由内核决定的,与进程是否退出无关。有名信号量的api为:sem_open、sem_close、sem_unlink。

附加: 

 信号量知识也可参考下面链接:

信号量详解_信号量取值范围怎么求_FangYwang的博客-CSDN博客

信号量--System V信号量 与 Posix信号量-云社区-华为云 (huaweicloud.com)

System V信号量 与 Posix 信号量_分别使用 posix 信号量机制和 system v 信号量机制实现。_luren2015的博客-CSDN博客

SystemV信号量与POSIX信号量简介_执假以为真的博客-CSDN博客

Linux IPC 信号量:PV原语,PV操作,函数semget,函数semop、函数semctl、生产者和消费者模型_linux semop_不会code的菜鸟的博客-CSDN博客 

信号量的操作——semop函数 - 小葫芦藤 - 博客园 (cnblogs.com)

 用信号量为共享内存添加同步机制 - tp_16b - 博客园 (cnblogs.com)

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

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

相关文章

win下tomcat部署问题积累

1、win下双击tomcat的start.bat出现闪退 检查环境变量是否配置正确&#xff1a; 1.在已解压的tomcat的bin文件夹下找到startup.bat&#xff0c;右击->编辑。在文件头加入下面两行&#xff1a; SET JAVA_HOMED:\Java\jdk1.6.0_10 &#xff08;java jdk目录&#xff09;S…

【C语言进阶】程序环境和预处理

&#x1f525;博客主页&#xff1a;小王又困了 &#x1f4da;系列专栏&#xff1a;C语言 &#x1f31f;人之为学&#xff0c;不日近则日退 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 目录 一、程序的翻译环境和执行环境 二、详解编译和链接 2.1翻译环境 2.2编译的过…

Centos yum install出现Error: Unable to find a match: epel-release的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

MySQL基础扎实——MySQL中有哪几种锁

常见锁举例 在MySQL中&#xff0c;常见的锁包括以下几种&#xff1a; 表级锁&#xff08;Table-level Lock&#xff09;&#xff1a;表级锁是对整张表进行锁定&#xff0c;可以分为两种类型&#xff1a; 共享锁&#xff08;Shared Lock&#xff09;&#xff1a;也称为读锁&…

Google Earth Engine谷歌地球引擎提取多波段长期反射率数据后绘制折线图并导出为Excel

本文介绍在谷歌地球引擎GEE中&#xff0c;提取多年遥感影像多个不同波段的反射率数据&#xff0c;在GEE内绘制各波段的长时间序列走势曲线图&#xff0c;并将各波段的反射率数据与其对应的成像日期一起导出为.csv文件的方法。 本文是谷歌地球引擎&#xff08;Google Earth Engi…

Python图像处理【13】使用PIL执行图像降噪

使用PIL执行图像降噪 0. 前言1. 均值滤波器1.1 均值滤波器原理1.2 使用均值滤波器去除椒盐噪声 2. 高斯滤波器2.1 高斯滤波器原理2.2 使用高斯模糊滤波器去除椒盐噪声 3. 中值滤波器3.1 中值滤波器原理3.2 使用中值滤波器去除椒盐噪声 小结系列链接 0. 前言 在本节中&#xff…

MAXENT模型的生物多样性教程

详情点击链接&#xff1a;基于MAXENT模型的生物多样性生境模拟与保护优先区甄选、自然保护区布局优化及未来气候变化下评估中的应用及论文写作 一&#xff1a;生物多样性保护格局与自然保护区格局优化 1.我国生物多样性格局与分布&#xff1b; 2.我国自然保护区格局与分布&…

Emacs之改造搜索文件fd-dired(基于fd命令)(一百二十一)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

【【51单片机AD转换模块】】

代码是简单的&#xff0c;板子是坏的&#xff0c;电阻是识别不出来的 main.c #include <REGX52.H> #include "delay.h" #include "LCD1602.h" #include "XPT2046.h"unsigned int ADValue;void main(void) {LCD_Init();LCD_ShowString(1,1…

format格式化输出语法详解

hello&#xff0c;这里是Token_w的文章&#xff0c;主要讲解python的基础学习&#xff0c;希望对大家有所帮助 整理不易&#xff0c;感觉还不错的可以点赞收藏评论支持&#xff0c;感谢&#xff01; 使用 % 操作符对各种类型的数据进行格式化输出&#xff0c;这是早期 Python提…

文档、视频、图片上传(点击、拖拽、批量导入)要‍‍‍‍怎么实现?!

文章目录 Excel上传和图片视频上传Excel上传页面中的使用图片和视频上传的错误提醒以及逻辑处理上传进度处理 Excel上传和图片视频上传 Excel上传 excel的上传其实分为两步&#xff1a; 1、下载excel模板 2、上传excel模板 在项目中涉及到excel的业务&#xff0c;基本上都…

Neo4j

存储结构 参考&#xff1a; 《图数据库&#xff08;第二版&#xff09;》 https://www.jianshu.com/p/94c1166eb400 https://blog.csdn.net/sinat_32336967/article/details/103348528 更新日期&#xff1a;2022-8-18 Neo4j版本&#xff1a;4.4 类型ID长度&#xff08;bit&…

使用Ensp配置DHCP协议

如何使用Ensp配置DHCP协议&#xff0c;为PC自动分配IP地址 什么是DHCP&#xff1f; Dynamic Host Configuration Protocol&#xff0c;动态主机配置协议&#xff0c;简单理解为自动分配IP地址&#xff0c;有了这个协议就不用手动配置IP地址了&#xff0c;如图 思路 给路由…

Monkey日志分析

1. Monkey日志详解 Monkey日志由以下几部分组成&#xff1a; 测试命令信息 随机种子seed、运行次数、可运行应用列表、各事件百分比。 App切换和Activity跳转 可以看到切换到了哪个App&#xff0c;从哪个Activity跳转到了哪个Activity&#xff0c;如果发生了异常&#xff0c…

JVM详解(超详细)

目录 JVM 的简介 JVM 执行流程 JVM 运行时数据区 由五部分组成 JVM 的类加载机制 类加载的过程(五个) 双亲委派模型 类加载器 双亲委派模型的优点 JVM 中的垃圾回收策略 GC GC 中主要分成两个阶段 死亡对象的判断算法 引用计数算法 可达性分析算法 垃圾回收算…

Mac m1 下eclipse下载及jdk环境变量配置

一、安装eclipse 1、下载eclipse Eclipse downloads - Select a mirror | The Eclipse Foundation 此版本为m1芯片适用版本 2、下载后下一步安装即可 安装成功后&#xff0c;可以看到图标&#xff1a; 二、安装jdk 1、下载jdk 下载此版本即可&#xff0c;下载完成之后一直…

Linux系统中的SQL语句

本节主要学习&#xff0c;SQL语句的语句类型&#xff0c;数据库操作&#xff0c;数据表操作&#xff0c;和数据操作等。 文章目录 一、SQL语句类型 DDL DML DCL DQL 二、数据库操作 1.查看 2.创建 默认字符集 指定字符集 3.进入 4.删除 5.更改 库名称 字符集 6…

(十三)定时任务

以下内容来自 尚硅谷&#xff0c;写这一系列的文章&#xff0c;主要是为了方便后续自己的查看&#xff0c;不用带着个PDF找来找去的&#xff0c;太麻烦&#xff01; 第 13 章 定时任务 13.1 什么是定时任务 1、InfluxDB任务是一个定时执行的FLUX脚本&#xff0c;它先查询数据…

小程序创建

1&#xff0c;下载HBuilder X ;(3.8.7) HBuilderX-高效极客技巧 2,下载模板&#xff08;不选云服务的&#xff09;&#xff1b; 3&#xff0c;运行-运行到小程序模拟器&#xff1b; 4&#xff0c;安装小程序开发工具&#xff1b; 5&#xff0c;选择稳定版-windows64版&…