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

输出:

相关推荐
Mr. zhihao10 分钟前
装饰器模式详解:动态扩展对象功能的优雅解决方案
java·开发语言·装饰器模式
zyhomepage11 分钟前
科技的成就(六十四)
开发语言·人工智能·科技·算法·内容运营
hero_th13 分钟前
[Ubuntu] 文件/目录权限更改
linux·ubuntu
Ethan Wilson17 分钟前
C++/QT可用的websocket库
开发语言·c++·websocket
花花少年23 分钟前
pip在ubuntu下换源
linux·ubuntu·pip
y0ungsheep42 分钟前
[GXYCTF 2019]Ping Ping Ping 题解(多种解题方式)
linux·web安全·网络安全·php
海绵波波1071 小时前
Webserver(1.6)Linux系统IO函数
linux·运维·服务器
爱编程— 的小李1 小时前
开关灯问题(c语言)
c语言·算法·1024程序员节
小宇1 小时前
The valid characters are defined in RFC 7230 and RFC 3986
java·开发语言·后端·tomcat
尘浮生1 小时前
Java项目实战II基于Spring Boot的美食烹饪互动平台的设计与实现(开发文档+数据库+源码)
java·开发语言·数据库·spring boot·微信小程序·小程序·美食