IPC 进程间通信 信号量集合 Linux环境 C语言实现

只用于多进程间的并发控制

一个信息量集合(信号量集 或 信息量数组)中顺序存储着多个信号量


相关接口函数:


实际项目,直接调用semop函数来作为某个或某几个信号量的PV操作函数会很不方便,因此会对信号量集合的接口进行二次封装,封装方案:
1. 项目中用到几个信号量就创建几个信号量集合,每个信号量集合中仅包含一个信号量,然后基于每个信号量集合封装相应的初始化、P、V操作函数
**2.**项目中创建一个信号量集合,该集合包含所有需要的信号量,然后针对每个信号量封装它的初始化、P、V操作函数

一般建议项目中使用的信号量比较少时用第1方案,否则使用第2方案

以下采用第2方案:

cpp 复制代码
#define SEM_NUM ?

union semun
{
	int val;
	unsigned short *pval;
};

// create_and_init_sem_set() 创建并初始化
int create_and_init_sem_set(const char *pathname,int no,unsigned short *pallval,int semnum);

// sem_p_by_index() p操作
int sem_p_by_index(int semid,int index,int shrnum);

// sem_v_by_index() v操作
int sem_v_by_index(int semid,int index,int shrnum);

/*针对集合中下标为0的信号量编写PV操作带参宏*/
#define sem_0_p(semid,shrnum) sem_p_by_index(semid,0,shrnum)
#define sem_0_v(semid,shrnum) sem_v_by_index(semid,0,shrnum)

/*针对集合中下标为1的信号量编写PV操作带参宏*/
#define sem_1_p(semid,shrnum) sem_p_by_index(semid,1,shrnum)
#define sem_1_v(semid,shrnum) sem_v_by_index(semid,1,shrnum)
。。。。。。
/*针对集合中下标为x的信号量编写PV操作带参宏*/
#define sem_x_p(semid,shrnum) sem_p_by_index(semid,x,shrnum)
#define sem_x_v(semid,shrnum) sem_v_by_index(semid,x,shrnum)

示例代码:

my_semset.h

cpp 复制代码
#ifndef MY_SEMSET_H
#define MY_SEMSET_H

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

#define MY_SEM_NUM 1

union semun{ // 信号量集合
    int val;
    unsigned short *pvals;
};

// create_and_init_sem_set() 创建并初始化
int create_and_init_semset(const char *pathname,int no,unsigned short *pallval,int valnum);

// sem_p_by_index() p操作
int sem_p_by_index(int semid,int index,int shrnum);

// sem_v_by_index() v操作
int sem_v_by_index(int semid,int index,int shrnum);

#define sem_0_p(semid,shrnum) sem_p_by_index(semid,0,shrnum)
#define sem_0_v(semid,shrnum) sem_v_by_index(semid,0,shrnum)

#if 0
#define sem_1_p(semid,shrnum) sem_p_by_index(semid,1,shrnum)
#define sem_1_v(semid,shrnum) sem_v_by_index(semid,1,shrnum)

#define sem_2_p(semid,shrnum) sem_p_by_index(semid,2,shrnum)
#define sem_2_v(semid,shrnum) sem_v_by_index(semid,2,shrnum)
#endif

#endif

my_semset.c

cpp 复制代码
#include "my_semset.h"

int create_and_init_semset(const char *pathname,int no,unsigned short *pallval,int valnum){
    key_t key;
    int semid = -1;
    union semun un;

    if(valnum < MY_SEM_NUM){
        printf("The valnum is too small\n");
        return -1;
    }

    key = ftok(pathname,no); // ftok() 获取key值

    semid = semget(key,MY_SEM_NUM,IPC_CREAT | IPC_EXCL | 0666); // semget() 获取id
    if(semid < 0){ // semset is exist 已经存在就不用初始化了直接获取
        semid = semget(key,MY_SEM_NUM,IPC_CREAT | 0666);
    }
    else{ // semset is not exist 不存在需要先创建再调用semctl()初始化
        un.pvals = pallval;
        semctl(semid,0,SETALL,un); // semctl()设置初值
    }

    return semid;
}

int sem_p_by_index(int semid,int index,int shrnum){
    struct sembuf op;

    if(shrnum <= 0){
        printf("shrnum = %d is invalid\n",shrnum);
        return -1;
    }

    op.sem_num = index;
    op.sem_op = -shrnum;
    op.sem_flg = SEM_UNDO;

    return semop(semid,&op,1);
}

int sem_v_by_index(int semid,int index,int shrnum){
    struct sembuf op;

    if(shrnum <= 0){
        printf("shrnum = %d is invalid\n",shrnum);
        return -1;
    }

    op.sem_num = index;
    op.sem_op = shrnum;
    op.sem_flg = 0;

    return semop(semid,&op,1);
}

input.c

cpp 复制代码
#include "../../semset/my_semset.h"
#include <sys/ipc.h>
#include <sys/shm.h>

char *input_string(char *buf,int size);

int main(int argc, char *argv[]){
    unsigned short val = 0;
    int semid = create_and_init_semset("./input.c",8,&val,1);
    key_t shmkey;
    int shmid = -1;
    char *pshm = NULL;

    shmkey = ftok("./input.c",88); // 获取input.c的key值
    shmid = shmget(shmkey,40,IPC_CREAT | 0666); // shmget() 创建并打开一个共享内存,获取id
    pshm = shmat(shmid,NULL,0); // shmat() 获取指定内存块的首地址

    while(1){
        printf("Please input a string:\n");
        input_string(pshm,40); // 读到共享内存中
        sem_0_v(semid,1); // v操作
        if(strcmp(pshm,"byebye") == 0)  break; // 出口
    }

    shmdt(pshm); //shmdt()
    pshm = NULL;

    return 0;
}

output.c

cpp 复制代码
#include "../../semset/my_semset.h"
#include <sys/ipc.h>
#include <sys/shm.h>

char *input_string(char *buf,int size);

int main(int argc, char *argv[]){
    unsigned short val = 0;
    int semid = create_and_init_semset("./input.c",8,&val,1); // create_and_innit()
    key_t shmkey;
    int shmid = -1;
    char *pshm = NULL;

    shmkey = ftok("./input.c",88); // ftok()

    shmid = shmget(shmkey,40,IPC_CREAT | 0666); // shmget() 创建并打开一个共享内存
    pshm = shmat(shmid,NULL,0); // shmat() 获取指定内存块的首地址

    while(1){
        sem_0_p(semid,1); // p操作
        if(strcmp(pshm,"byebye") == 0)  break; // 出口
        else    printf("the input string is %s\n",pshm);
    }

    shmdt(pshm); // shmdt()
    pshm = NULL;

    return 0;
}

input_string.c ( 读取 size 个数据存到 buf 里返回**)**

cpp 复制代码
#include <stdio.h>
#include <string.h>

char *input_string(char *buf,int size){
    int len = 0;

    fgets(buf,size,stdin);
    len = strlen(buf);

    if(*(buf + len - 1) == '\n')    *(buf + len - 1) = '\0';
    else    while(getchar() != '\n'){}

    return buf;
}

输出:

相关推荐
shinelord明3 分钟前
【再谈设计模式】享元模式~对象共享的优化妙手
开发语言·数据结构·算法·设计模式·软件工程
Monly2110 分钟前
Java(若依):修改Tomcat的版本
java·开发语言·tomcat
boligongzhu11 分钟前
DALSA工业相机SDK二次开发(图像采集及保存)C#版
开发语言·c#·dalsa
Eric.Lee202111 分钟前
moviepy将图片序列制作成视频并加载字幕 - python 实现
开发语言·python·音视频·moviepy·字幕视频合成·图像制作为视频
7yewh14 分钟前
嵌入式Linux QT+OpenCV基于人脸识别的考勤系统 项目
linux·开发语言·arm开发·驱动开发·qt·opencv·嵌入式linux
小张认为的测试18 分钟前
Linux性能监控命令_nmon 安装与使用以及生成分析Excel图表
linux·服务器·测试工具·自动化·php·excel·压力测试
waicsdn_haha25 分钟前
Java/JDK下载、安装及环境配置超详细教程【Windows10、macOS和Linux图文详解】
java·运维·服务器·开发语言·windows·后端·jdk
嵌入式科普26 分钟前
十三、从0开始卷出一个新项目之瑞萨RZN2L串口DMA接收不定长
c语言·stm32·瑞萨·e2studio·rzn2l
打鱼又晒网26 分钟前
linux网络套接字 | 深度解析守护进程 | 实现tcp服务守护进程化
linux·网络协议·计算机网络·tcp
_WndProc27 分钟前
C++ 日志输出
开发语言·c++·算法