Linux进程间通信-semaphore信号量

信号量

? 信号量是一个计数器,可以用来控制多个线程对共享资源的访问.它不是用于交换大批数据,而用于多线程之间的同步.它常作为一种锁机制,防止某进程在访问资源时其它进程也访问该资源.因此,主要作为进程间以及同一个进程内不同线程之间的同步手段[1].

? 简单的可以认为信号量就是一个数字, semctl函数用来直接控制信号量信息. semop 函数可以增大或者减小这个数字. 如果减小后的数字小于0, 那么线程或进程阻塞直到减小后的数字大于等于0.

? 信号量与互斥锁的不同: 1. 只有持有锁的线程才能释放锁, 而信号量的值的修改可以在任何不同的线程中进行; 2. 互斥锁最多只能被一个线程持有, 效果与值为1信号量(好像又叫做二元信号量吧)一样. 而信号量的值可以被多个线程减小.

相关接口

使用这些接口之前需要先引入这些头文件

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
  • semget : 创建一组新信号量或取得一组已有信号量

//key : 通过ftok()获取
//nsems : 这一组信号量中有多少个信号量
//semflg : 一组标记, IPC_CREATE | 0644 
//返回值: 成功返回信号量集的id. 失败返回-1
int semget(key_t key, int nsems, int semflg);

  • semctl : 函数用来直接控制信号量信息
//semid : 信号量集的id
//semnum : 信号量集中的第几个信号量, 从0开始
//cmd : 对信号量进行的操作
//是传第四个参数有cmd决定的
int semctl(int semid, int semnum, int cmd, ...);

//如果需要传递第四个参数. 需要用户自定义如下的共用体作为第四个参数传入
union semun {
  int              val;    /* Value for SETVAL */
  struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
  unsigned short  *array;  /* Array for GETALL, SETALL */
  struct seminfo  *__buf;  /* Buffer for IPC_INFO(Linux-specific) */
};

从共用体semun的定义就可看出哪些cmd需要传递 第四个参数(注释大写的内同) . 用的比较多的是SETVAL 用来设置信号量的值.

  • semop : 改变信号量的值
//semid: 信号量集的id
//sops: 结构体数组
//nsops: 数组长度
int semop(int semid, struct sembuf *sops, size_t nsops);

struct sembuf{
  unsigned short sem_num;  /* semaphore number */ //信号量集中的第几个信号量
  short          sem_op;   /* semaphore operation */ //信号量的值改变量, 整数时信号量的值增大, 负数时减小
  short          sem_flg;  /* operation flags *///SEM_UNDO: 进程结束后自动恢复该进程对信号量修改
};

简单的代码实例

//创建有n个信号量的信号量集, 并返回信号量集的id
int creat_sem(const char *path, int proj_id, int nsems){
    int sem_id;
    key_t key = ftok(path, proj_id);

    if ((sem_id = semget(key, nsems, IPC_CREAT | 0644)) < 0) {
        return -1;
    }

    return sem_id;
}
//为sem_id的信号量集中每个信号量设置值
int init_sem(int sem_id, int nsems, int value){
    for (int i = 0; i < nsems; ++i) {
        union semun arg;
        arg.val = value;
        int ret = semctl(sem_id,i,SETVAL, arg);
        if (ret < 0) {
            return -1;
        }
    }
    return 0;
}
//对信号量集中第sem_num+1个信号量的值减一
int P(int sem_id, int sem_num){
    struct sembuf sbuf;
    sbuf.sem_num = sem_num;
    sbuf.sem_op = -1;
    sbuf.sem_flg = SEM_UNDO;
    if (semop(sem_id, &sbuf, 1) < 0) {
        return -1;
    }
    return 0;
}
//对信号量集中第sem_num+1个信号量的值加一
int V(int sem_id, int sem_num){
    struct sembuf sbuf;
    sbuf.sem_num = sem_num;
    sbuf.sem_op = 1;
    sbuf.sem_flg = SEM_UNDO;
    if (semop(sem_id, &sbuf, 1) < 0) {
        return -1;
    }
    return 0;
}

参考文章:
[1]https://www.linuxprobe.com/linux-process-method.html?ivk_sa=1024320u

Linux进程间通信-semaphore信号量

上一篇:Linux的链接(入门)


下一篇:Linux命令总结