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;
}

输出:

相关推荐
tellmewhoisi12 小时前
linux 基础知识(文件权限相关)
linux·运维·服务器
jiayong2312 小时前
Claude Code 常见操作实战指南
linux·服务器·网络·ai·claude·claude code
兰令水12 小时前
leecodecode【回溯子集】【2026.6.4打卡-java版本】
java·开发语言·深度优先
bubiyoushang88812 小时前
基于 C/C++ 的 MQTT 物联网通信协议实现
c语言·c++·物联网
fox_lht12 小时前
14.3.重构
开发语言·后端·rust
醇氧12 小时前
【Linux 】sudo、sudo -i、su、su - 完整区别总结
linux·运维·服务器
牛油果子哥q12 小时前
【C++ const 】全场景深度精讲:修饰规则、底层常量折叠、指针 / 引用 / 成员函数实战、易错坑点与工程代码实现
开发语言·c++
xiaoye-duck12 小时前
《Linux系统编程》System V IPC 进阶:消息队列与信号量从入门到内核
linux
天天进步201512 小时前
Python全栈项目--社区问答平台
开发语言·python·django
代码熬夜敲Q12 小时前
网络工程相关
linux·服务器·网络