当前位置: 首页 > news >正文

Linux中的信号量

目录

信号量概念

定义

操作

类型

应用

信号量封装

一、创建信号量

头文件

函数原型

参数说明

返回值

示例

二、设置信号量初始值

头文件

函数原型

参数解释

返回值

示例

三、信号量的P操作

头文件

函数原型

参数解释

返回值

示例

四、信号量的V操作

示例


信号量概念

定义

        信号量是一种用于多进程 / 线程同步的整数变量,用于控制对共享资源的访问。凡是遇到内存操作就可以实现加锁。

操作

        P 操作:信号量值减 1,若值小于 0 则进程阻塞,否则继续执行。

        V 操作:信号量值加 1,若有进程阻塞则唤醒一个。

类型

        二进制信号量:值为 0 或 1,用于互斥访问。        

        ​​​​​计数信号量:值为非负整数,控制多资源访问。

应用

        互斥访问:确保同一时间只有一个进程 / 线程访问共享资源。

        资源管理:控制对多个相同资源的并发访问。

        进程同步:保证进程或线程按顺序执行。

信号量封装

1、创建/获取信号量

2、设置初始值,一般为1

3、P操作

4、V操作

一、创建信号量

        semctl 是一个在 Unix 和类 Unix 系统中用于控制信号量集的系统调用函数。

头文件

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

函数原型

int semget(key_t key, int nsems, int semflg);

参数说明

        key:唯一标识。

        nsems:要创建的信号量集中信号量的数量。

       semflg:标志位,用于指定创建信号量集的权限和其他选项。它可以是以下值的组合:           

                IPC_CREAT:如果信号量集不存在,则创建它。

                IPC_EXCL:与 IPC_CREAT 一起使用,如果信号量集已经存在,则返回错误。

                权限标志(如 0666):指定信号量集的访问权限。

返回值

        成功时,返回一个非负整数,即信号量集的标识符(semaphore identifier),后续的信号量操作将使用这个标识符。

        失败时,返回 -1,并设置 errno 以指示错误类型。

示例

int sem_create(key_t key, int num_sems)
{int res = 0;res = semget(key, num_sems, IPC_CREAT | 0666);if (res < 0){perror("semget error");}return res;
}

二、设置信号量初始值

        semctl 是类 Unix 系统中用于控制信号量集的一个系统调用,借助它能够对信号量集进行多种操作,例如设置信号量的值、获取信号量的值、删除信号量集等。

头文件

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

函数原型

int semctl(int semid, int semindex, int cmd, ...);

参数解释

        semid:信号量集的标识符,由 semget 函数返回,用于指定要操作的信号量集。

        semindex:为第几个信号量设置值。

        cmd:要执行的命令,常见的命令如下:

                SETVAL:把单个信号量的值设置为传入的参数值。

                GETVAL:获取单个信号量的值。

                SETALL:设置信号量集中所有信号量的值。

                GETALL:获取信号量集中所有信号量的值。

                IPC_RMID:删除信号量集。

        ...:这是可选参数,依据 cmd 的不同而有所不同。在使用 SETVAL 或 SETALL 时,需要传入对应的参数值。通常使用 union semun 类型的变量来传递该参数,union semun 的定义如下:

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) */
};

返回值

        成功时,依据 cmd 的不同返回不同的值。例如,GETVAL 命令返回信号量的值,IPC_RMID 命令成功时返回 0。

        失败时,返回 -1,并设置 errno 以指示错误类型。

示例

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) */
};int sem_setval(int semid, int semindex, int val)
{union semun arg;arg.val = val;int res = semctl(semid, semindex, SETVAL, arg);if (res < 0){perror("semctl error");}return res;
}

三、信号量的P操作

        semop 是类 Unix 系统中用于对信号量集进行操作的系统调用,它允许进程原子性地对一个或多个信号量进行改变,常用于实现进程间的同步和互斥。

头文件

#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 结构体定义了对信号量的具体操作,其结构如下:

struct sembuf 
{unsigned short sem_num;  // 信号量集中信号量的编号,从 0 开始short          sem_op;   // 对信号量的操作值short          sem_flg;  // 操作标志
};

        sem_num:指定要操作的信号量在信号量集中的编号。

        sem_op:表示对信号量的操作值,有以下几种情况:

                若 sem_op 为正数,则表示释放相应数量的资源,信号量的值会增加 sem_op

                若 sem_op 为负数,则表示请求相应数量的资源,信号量的值会减少 sem_op。若信号量当前值小于 |sem_op|,则进程可能会阻塞,具体取决于 sem_flg

                若 sem_op 为 0,则表示等待信号量的值变为 0。

        sem_flg:操作标志,常用的标志有:

                IPC_NOWAIT:若操作不能立即执行,则不阻塞,直接返回错误。

                SEM_UNDO:当进程终止时,系统会自动撤销该进程对信号量的操作。

        nsopssops 数组中元素的个数,即要执行的操作数量。

返回值

        成功时,返回 0。

        失败时,返回 -1,并设置 errno 以指示错误类型。

示例

// 3、信号量的P操作
int sem_p(int semid, int semindex)
{int res = 0;struct sembuf buf = { semindex,-1,SEM_UNDO };res = semop(semid, &buf, 1);if (res < 0){perror("sem_p error");}return res;
}

四、信号量的V操作

        v操作唯一的变化就是从-1变成+1

示例

// 4、信号量的V操作
int sem_v(int semid, int semindex)
{int res = 0;struct sembuf buf = { semindex,1,SEM_UNDO };res = semop(semid, &buf, 1);if (res < 0){perror("sem_p error");}return res;
}

相关文章:

  • 【python】deepcopy深拷贝浅拷贝(结合例子理解)
  • 3分钟极速部署MySQL:brew/apt/yum全平台一条龙实战
  • 【计算机网络 | 第三篇】常见的网络协议(二)
  • 数据结构实验7.1:二叉树的遍历
  • WIN10重启开机不用登录,直接进入桌面
  • Mysql insert一条数据的详细过程
  • C语言求执行次数
  • 【牛客练习赛137 C】题解
  • 开发工具~
  • Android音视频开发
  • Vue.js核心功能实现
  • 计算机视觉与深度学习 | TensorFlow基本概念与应用场景:MNIST 手写数字识别(附代码)
  • Mamba模型时间序列预测
  • Java创建对象的方式
  • 中级软件设计师 - 知识点(附真题)目录大全
  • 2025年4月19日-美团春招笔试题-第三题
  • Java synchroinzed和ReentrantLock
  • IDEA连接达梦数据库
  • NumPy:数值计算基础与高性能数组操作
  • 约束:常见约束(常见约束-例子,外键约束)
  • 聚焦客户真实需求,平安人寿重磅推出“添平安”保险+服务解决方案
  • 协信远创620亿元债务重整计划获法院批准:冯仑入局,部分核心资产已提前转让
  • 贵州赤水“整改复耕”:为何竹林砍了,地却荒了?
  • 女子拿蘸料时触电受伤,海底捞回应
  • 一季度浙江实现生产总值22300亿元,同比增长6.0%
  • 广西柳州23年的蝶变:从“酸雨之城”到“文明之城”