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

输出:

相关推荐
一个小坑货7 分钟前
Cargo Rust 的包管理器
开发语言·后端·rust
bluebonnet2711 分钟前
【Rust练习】22.HashMap
开发语言·后端·rust
古月居GYH12 分钟前
在C++上实现反射用法
java·开发语言·c++
糖豆豆今天也要努力鸭13 分钟前
torch.__version__的torch版本和conda list的torch版本不一致
linux·pytorch·python·深度学习·conda·torch
烦躁的大鼻嘎21 分钟前
【Linux】深入理解GCC/G++编译流程及库文件管理
linux·运维·服务器
ac.char28 分钟前
在 Ubuntu 上安装 Yarn 环境
linux·运维·服务器·ubuntu
敲上瘾28 分钟前
操作系统的理解
linux·运维·服务器·c++·大模型·操作系统·aigc
在下不上天37 分钟前
Flume日志采集系统的部署,实现flume负载均衡,flume故障恢复
大数据·开发语言·python
长弓聊编程1 小时前
Linux系统使用valgrind分析C++程序内存资源使用情况
linux·c++
陌小呆^O^1 小时前
Cmakelist.txt之win-c-udp-client
c语言·开发语言·udp