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

【Linux】System V —— 基于建造者模式的信号量

目录

一、信号量和P、V原语

1.1 信号量常规理解

1.2 信号量值含义

1.3 信号量结构体伪代码

1.4 P原语

1.5 V原语

1.6 信号量集结构体

二、信号量操作接口

2.1 semget

2.2 semctl

2.3 semop

三、封装Sem


一、信号量和P、V原语

信号量和P、V原语由Dijkstra(迪杰斯特拉)提出。

1.1 信号量常规理解

  • 执行流间互斥和同步

1.2 信号量值含义

  • S>0:S 表示可用资源的个数
  • S=0:表示无资源可用,无等待进程
  • S<0:|S| 表示等待队列中进程个数

1.3 信号量结构体伪代码

// 信号量本质是一个计数器struct semaphore
{int value;pointer_PCB queue;
}

1.4 P原语

P(s)
{s.value = s.value--;if (s.value < 0){// 该进程状态置为等待状状态// 将该进程的PCB插⼊⼊相应的等待队列s.queue末尾}
}

1.5 V原语

V(s)
{s.value = s.value++;if (s.value > 0){// 唤醒相应等待队列s.queue中等待的⼀⼀个进程// 改变其状态为就绪态// 并将其插⼊OS就绪队列}
}

1.6 信号量集结构体

The semid_ds data structure is defined in<sys / sem.h> as follows : 
struct semid_ds
{struct ipc_perm sem_perm; /* Ownership and permissions */time_t sem_otime;         /* Last semop time */time_t sem_ctime;         /* Last change time */unsigned long sem_nsems;  /* No. of semaphores in set */
};The ipc_perm structure is defined as follows(the highlighted fields are settable using IPC_SET) : 
struct ipc_perm
{key_t __key;          /* Key supplied to semget(2) */uid_t uid;            /* Effective UID of owner */gid_t gid;            /* Effective GID of owner */uid_t cuid;           /* Effective UID of creator */gid_t cgid;           /* Effective GID of creator */unsigned short mode;  /* Permissions */unsigned short __seq; /* Sequence number */
};

二、信号量操作接口

2.1 semget

NAME

        semget - get a System V semaphore set identifier

SYNOPSIS

        #include <sys/types.h>

        #include <sys/sem.h>

        #include <sys/ipc.h>

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

RETURN VALUE

        On success, semget() returns the semaphore set identifier (a nonnegative integer).  On failure, -1 is returned, and errno is set to indicate the error.

参数介绍:

  • key:信号量集的键值,同消息队列和共享内存
  • nsems:信号量集中信号量的个数
  • semflg:同消息队列和共享内存

2.2 semctl

NAME

        semctl - System V semaphore control operations

SYNOPSIS

        #include <sys/types.h>

        #include <sys/ipc.h>

        #include <sys/sem.h>

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

This function has three or four arguments, depending on op.  When there are four, the fourth has the type union semun.  The calling program must define this union as follows:

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

RETURN VALUE
       On success, semctl() returns a nonnegative value depending on op as follows:

       GETNCNT
              the value of semncnt.

       GETPID the value of sempid.

       GETVAL the value of semval.

       GETZCNT
              the value of semzcnt.

       IPC_INFO
              the index of the highest used entry in the kernel's internal array recording information about all semaphore sets.  (This  information  can  be  used  with  repeated  SEM_STAT  or
              SEM_STAT_ANY operations to obtain information about all semaphore sets on the system.)

       SEM_INFO
              as for IPC_INFO.

       SEM_STAT
              the identifier of the semaphore set whose index was given in semid.

       SEM_STAT_ANY
              as for SEM_STAT.

       All other op values return 0 on success.

       On failure, semctl() returns -1 and sets errno to indicate the error.

参数介绍:

1. semid:

  • 信号量集的标识符(由 semget() 创建)

2. semnum:

  • 信号量在集合中的索引(从0开始)
  • 对单个信号量操作时:指定目标信号量
  • 对整组操作时(如 IPC_RMID):此参数被忽略

3. cmd:控制命令

常用命令及作用:

命令功能是否需要第四个参数
IPC_STAT获取信号量集状态信息是(struct semid_ds*
IPC_SET修改信号量集权限是(struct semid_ds*
IPC_RMID立即删除信号量集
GETVAL获取单个信号量值
SETVAL设置单个信号量值是(int
GETALL获取所有信号量值是(unsigned short*
SETALL设置所有信号量值是(unsigned short*
GETPID获取最后操作进程PID
GETNCNT获取等待信号量增加的进程数
GETZCNT获取等待信号量为零的进程数

4. 第四个参数(可变参数):

  • 类型:联合体 semun(需用户自定义)
  • // 定义示例union semun {int              val;    // SETVAL 使用struct semid_ds *buf;    // IPC_STAT/IPC_SET 使用unsigned short  *array;  // GETALL/SETALL 使用
    };
  • 作用:根据 cmd 传递特定数据

2.3 semop

NAME

        semop, semtimedop - System V semaphore operations

SYNOPSIS

        #include <sys/types.h>

        #include <sys/ipc.h>

        #include <sys/sem.h>

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

RETURN VALUE

        On success, semop() and semtimedop() return 0.  On failure, they return -1, and set errno to indicate the error.

参数介绍:

1. semid:

  • 信号量集的标识符(由 semget() 创建)
  • 需确保进程有操作权限(通过 semget() 的权限位设置)

2. sops(操作结构体指针):

  • 类型:struct sembuf *
  • 结构体定义:
  • struct sembuf {unsigned short sem_num;  // 信号量在集合中的索引short          sem_op;   // 操作类型(见下文)short          sem_flg;  // 操作标志
    };

成员详解:

1. sem_num:

  • 信号量在信号量集中的索引(从 0 开始)
  • 例如:集合包含 3 个信号量时,有效值为 012

2. sem_op(操作类型):

操作说明原子性保证
正数增加信号量值(释放资源),例如 sem_op=3 使信号量值 $S \leftarrow S + 3$立即执行,不阻塞
负数减少信号量值(请求资源),例如 sem_op=-2 需满足 $S \geq 2$,否则阻塞不满足条件时阻塞进程
0等待信号量值变为 $0$,若 $S \neq 0$ 则阻塞常用于同步操作

3. sem_flg(操作标志):

标志说明
IPC_NOWAIT非阻塞模式:若操作无法立即完成(如资源不足),直接返回错误 EAGAIN
SEM_UNDO进程退出时自动撤销操作(防止死锁),例如进程崩溃后自动恢复信号量原始值

3. nsops(操作数量):

  • 作用:指定sops,数组的长度(即要执行的操作数量)

三、封装Sem

// Sem.hpp#pragma once#include <iostream>
#include <string>
#include <memory>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <unistd.h>#define GET_SEM IPC_CREAT // 不给权限
#define BUILD_SEM (IPC_CREAT | IPC_EXCL | 0X666)const std::string pathname = "/tmp";
int project_id = 99;// 只关注使用和删除
class Semaphore
{
public:Semaphore(int semid, int flag):_semid(semid), _flag(flag){}void P() {struct sembuf bs; // 该结构体系统提供bs.sem_num = 0;bs.sem_op = -1;bs.sem_flg = SEM_UNDO;int n = ::semop(_semid, &bs, 1);if(n < 0) {perror("semop-P");}}void V() {struct sembuf bs; // 该结构体系统提供bs.sem_num = 0;bs.sem_op = 1;bs.sem_flg = SEM_UNDO;int n = ::semop(_semid, &bs, 1);if(n < 0) {perror("semop-V");}}~Semaphore() {if(_flag == GET_SEM) return;// 让信号量自动销毁// 如果销毁信号量集合:The argument semnum is ignoredint n = ::semctl(_semid, 0, IPC_RMID);if(n < 0) {perror("semctl");}std::cout << "sem set destory!" << std::endl;}
private:int _semid;int _flag;
};using sem_ptr = std::shared_ptr<Semaphore>;// 使用简单的建造者模式,用它来构建一个sem
class SemaphoreBuilder
{
public:SemaphoreBuilder():_val(-1){}SemaphoreBuilder& SetVal(int val) {_val = val;return *this; // 支持连续访问}sem_ptr Build(int flag) {if(_val < 0) {std::cout << "you must init first" << std::endl;return nullptr;}// 1. 申请key值key_t key = ::ftok(pathname.c_str(), project_id);if(key < 0) {perror("ftok");exit(1);}// 2. 根据初始值,创建一个信号量集int semid = ::semget(key, 1, flag);if(semid < 0) {perror("semget");exit(2);}if(BUILD_SEM == flag) {// 3. 初始化信号量union semun { // 该联合体系统不提供,需要自己定义int val;struct semid_ds *buf;unsigned short *array;struct seminfo *__buf;}un;un.val = _val; // 设置初始值int n = ::semctl(semid, 0, SETVAL, un);if(n < 0) {perror("semctl-set");exit(3);}}return std::make_shared<Semaphore>(semid, flag);}~SemaphoreBuilder(){}
private:int _val;
};
// Write.cc#include <cstdio>
#include <ctime>
#include <unistd.h>
#include "Sem.hpp"int main()
{SemaphoreBuilder sab;auto fsem = sab.SetVal(1).Build(BUILD_SEM); // 创建信号量集合,只有一个信号量,初始化为1,就是当成锁来用if (fork() == 0){auto csem = sab.Build(GET_SEM);int cnt = 9;while (cnt--){csem->P();std::cout << "c, sleep" << std::endl;sleep(1);std::cout << "csem: " << cnt << std::endl;sleep(1);csem->V();}exit(0);}int cnt = 16;while (cnt--){fsem->P();std::cout << "f, sleep" << std::endl;sleep(1);std::cout << "fsem: " << cnt << std::endl;sleep(1);fsem->V();}return 0;
}

http://www.dtcms.com/a/441691.html

相关文章:

  • VScode-ESP-IDF工程函数定义无法跳转且无注释提示
  • 最新的网站建设软件标书制作员工作内容
  • JAVA SE 基础语法 —— C / 运算符
  • SSM餐饮管理系统uto0o《开发全资源(程序 / 源码 / 数据库)+ 万言论文(文末)+ 系统界面》
  • 上饶市建设厅网站中国最新消息新冠疫苗最新消息
  • 安徽省建设银行网站关于网站建设的意见
  • 免费域名建站青岛网站有限公司
  • 广东泰通建设有限公司网站东莞人才网58
  • 什么是wap网站甘家口网站建设
  • 网站接电话中国关键词官网
  • 广州车陂网站建设公司wordpress如何修改博客模板
  • 沈阳谷歌网站建设金湖建设局网站
  • 淳化网站制作我自己的网站怎么做关键词优化
  • 深圳网站建设工作在线文字logo设计
  • 网站开发 聊天窗口镇平微网站开发
  • 网站平台延展性广州品牌网站设计价格
  • 网站开发合作意向书网站域名使用费用
  • 音乐网站的音乐怎么做音乐试听wordpress文章分页共多少页
  • 怎么选择做网站的公司专业建设情况
  • 申请网站空间是申请域名吗个人新闻类网站模板
  • 网站建设流程是什么意思解决方案网站设计
  • 网络公司 网站设计做衣服的教程网站
  • 网站内容创造深夜免费软件app下载
  • 广州网站建设亅新科送推广全国小微企业名录
  • 手机网站课程360优化大师历史版本
  • 网站都有什么类型的极简网站设计
  • 网站截图环境 php成品网站1688入口的功能介绍
  • 赶集网的二级域名网站怎么做分类信息网站建设模板
  • 郑州做网站华久科技开发一个电商网站
  • 中国建设部网站四库平台seo关键词排名优化如何