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

输出:

相关推荐
子超兄1 小时前
线程池相关问题
java·开发语言
坐吃山猪1 小时前
Python进度条
linux·服务器·python
IMPYLH2 小时前
Linux 的 b2sum 命令
linux·运维·服务器·bash
dinl_vin2 小时前
python:常用的基础工具包
开发语言·python
2301_793804692 小时前
C++中的适配器模式变体
开发语言·c++·算法
celeste03102 小时前
Redis Summary
linux·运维·服务器·redis·笔记
Jinkxs2 小时前
Java 部署:滚动更新(K8s RollingUpdate 策略)
java·开发语言·kubernetes
Sylvan.C2 小时前
Windows+Ubuntu 双系统安装超详细保姆级教程2026,包括系统安装、英伟达独显驱动安装以及双系统时间同步的所有过程
linux·运维·ubuntu
伴我与影2 小时前
Ubuntu 安装 NVIDIA 显卡驱动
linux·运维·ubuntu
unsynchronized2 小时前
OpenClaw 安装指南:Linux 与 Windows 系统详细教程
linux·运维·windows·ai