linux ipc通信 – 信号量

内容分享2小时前发布 Akitaaa
0 0 0

函数原型

/* Semaphore control operation.  */
extern int semctl (int __semid, int __semnum, int __cmd, ...) __THROW;

/* Get semaphore.  */
extern int semget (key_t __key, int __nsems, int __semflg) __THROW;

/* Operate on semaphore.  */
extern int semop (int __semid, struct sembuf *__sops, size_t __nsops) __THROW;

semget 函数介绍

int semget (key_t __key, int __nsems, int __semflg);
如果key不存在,且带有cteate标志则创建,如果已经存在则直接返回id

  • key:ipc的键,用于与semid匹配
  • nsems:信号聚焦信号的数量
  • flag:创建的控制选项
semctl 函数介绍

int semctl (int __semid, int __semnum, int __cmd, …);

  • semid 通过semget 返回的id
  • semnum 要操作第几个信号量
  • cmd 命令,支持的命名如下
命令 说明
IPC_STAT 从信号量集上检索semid_ds结构,并存到semun联合体参数的成员buf的地址中
IPC_SET 设置一个信号量集合的semid_ds结构中ipc_perm域的值,并从semun的buf中取出值
IPC_RMID 从内核中删除信号量集合
GETALL 从信号量集合中获得所有信号量的值,并把其整数值存到semun联合体成员的一个指针数组中
GETNCNT 返回当前等待资源的进程个数
GETPID 返回最后一个执行系统调用semop()进程的PID
GETVAL 返回信号量集合内单个信号量的值
GETZCNT 返回当前等待100%资源利用的进程个数
SETALL 与GETALL正好相反
SETVAL 用联合体中val成员的值设置信号量集合中单个信号量的值
semop 函数介绍

int semop (int __semid, struct sembuf *__sops, size_t __nsops)
对信号量聚焦的信号量进行加减操作

  • semid: semphore 句柄
  • ops 操作选项

struct sembuf {
    unsigned short sem_num; /* 需要操作的信号量编号 */
    short sem_op; /* 对信号量值进行加减的值 */
    short sem_flg; /* 操作选项 */
}

如果sem_op 为正值,表明对信号量进行v操作,会将信号量的值加上sem_op的值
如果sem_op 为负值,表明对信号量进行p操作,会将信号量的值减上sem_op绝对值,
如果减上之后小于0,如果指定了IPC_NOWAIT,则semop返回出错返回EAGAIN,如果没有指定则会阻塞

/* Mode bits for `msgget , `semget , and `shmget .  */
#define IPC_CREAT   01000       /* Create key if key does not exist. */
#define IPC_EXCL    02000       /* Fail if key exists.  */
#define IPC_NOWAIT  04000       /* Return error on wait.  */
后面3位是用户、用户组、其他用户的读写执行权限,如 0777
创建的时候要带上IPC_CREAT 和IPC_EXCL标志

/**
 * @file sem_lsw.c
 * @author lisiwen (lisiwen945@163.com)
 * @brief 实现两个进程的同步读写
 * @version 0.1
 * @date 2021-01-28
 *
 * @copyright Copyright (c) 2021
 *
 */
#include <apue.h>
#include <sys/sem.h>

union semun {
    int val;
    struct semid_ds *buf;
    unsigned short *array;
};

#define SEM_SEND 0
#define SEM_RECV 1

key_t key = 128;

// 创建信号量集,初始化semums个信号灯 和信号灯的值
int SemCreate(int value, int semnums) {
    // 创建信号箱集
    int semid = semget(key, semnums, IPC_CREAT | IPC_EXCL | 0777);
    if (semid < 0) {
        return -1;
    }
    union semun un;
    unsigned short *array = (unsigned short *)calloc(semnums, sizeof(unsigned short));
    for (int i = 0; i < semnums; i++) {
        array[i] = value;
    }
    un.array = array;
    // 初始化信号量聚焦所有信号量灯的值
    if (semctl(semid, 0, SETALL, un) < 0) {
        perror("semctl error");
        return -1;
    }
    free(array);
    printf("create semaphore %d success
", semid);
    return semid;
}

// 对信号量聚焦的具体的信号灯作PV操作, semnum 是要操作的第几个信号
// p 操作对信号的value -1
// v 操作对信号的value +1
void SemP(int semnum) {
    int semid = semget(key, 2, 0777);
    if (semid < 0) {
        perror("semget error
");
        return;
    }
    // 定义sembuf类型的结构体数组,放置若干个结构体变量
    // SEM_UNDO表明进程退出如果没有释放,则代为释放
    struct sembuf ops[] = {{semnum, -1, SEM_UNDO}};
    if (semop(semid, ops, sizeof(ops) / sizeof(struct sembuf)) < 0) {
        perror("semop error");
    }

}
void SemV(int semnum) {
    int semid = semget(key, 2, 0777);
    if (semid < 0) {
        perror("semget error
");
        return;
    }
    struct sembuf ops[] = {{semnum, 1, SEM_UNDO}};
    if (semop(semid, ops, sizeof(ops) / sizeof(struct sembuf)) < 0) {
        perror("semop error");
    }
}

// 销毁信号量集
void SemDel() {
    int semid = semget(key, 2, 0777);
    if (semid < 0) {
        perror("semget error
");
        return;
    }
    // 0 表明对所有信号量进行操作
    if (semctl(semid, 0, IPC_RMID, NULL) < 0) {
        perror("semop error");
    }
    printf("del semaphore %d success
", semid);
}

int main(int argc, char* argv[])
{
    if (argc < 2) {
        printf("%s arg", argv[0]);
    }

    if (strcmp(argv[1], "send") == 0) {
        for (int i = 0; i < 10; i++) {
            sleep(1);
            printf("send num %d
", i);
            SemV(SEM_SEND);
            SemP(SEM_RECV);
        }
    } else if (strcmp(argv[1], "recv") == 0) {
        for (int i = 0; i < 10; i++) {
            SemP(SEM_SEND);
            printf("recv num %d
", i);
            SemV(SEM_RECV);
        }
    } else if (strcmp(argv[1], "create") == 0) {
        int value = 0; // 初始value为0
        int semnums = 2; // 构建两个信号量
        SemCreate(value, semnums);
    } else if (strcmp(argv[1], "del") == 0) {
        SemDel();
    }
}

© 版权声明

相关文章

暂无评论

none
暂无评论...