liunx ipc 信号量

这里写目录标题

介绍

信号量准确的来说不算是一种ipc通信机制,更像是一种ipc通信的辅助机制,在信号量的约束下,不同进程访问共享资源或者临界资源的时候,会判断当前信号量是否满足访问条件。信号量是一个特殊的变量,程序对其访问都是原子操作。

原理

信号量只能进行两种操作 wait 和 signal 信号, 即P(sv)和V(sv) :
P(sv):如果sv的值大于零,就给它减1;如果它的值为零,就挂起该进程的执行
V(sv):如果有其他进程因等待sv而被挂起,就让它恢复运行,如果没有进程因等待sv而挂起,就给它加1.

举例说明:就是两个进程共享信号量sv,一旦A进程执行了P(sv)操作,它将得到信号量,并可以进入临界区,使sv减1,而因为sv为0,B进程将被阻止进入临界区,得不到P(sv)操作,它会被挂起以等待A进程离开临界区域并执行V(sv)释放信号量,之后B进程可以得到P(sv)操作,进入临界区进行操作。

函数

头文件 include<sys/sem.h>

int semget(key_t key, int num_sems, int sem_flags);

作用:创建一个新信号量或取得一个已有信号量。

参数1: key是整数值(非0值),两个进程之间可以通过它访问一个信号量,它代表程序可能要使用的某个资源,程序对所有信号量的访问都是间接的,程序先通过调用semget()函数并提供一个键再由系统生成一个相应的信号标识符(semget()函数的返回值),只有semget()函数才直接使用信号量键,所有其他的信号量函数使用由semget()函数返回的信号量标识符。如果多个程序使用相同的key值,key将负责协调工作。

参数2:num_sems指定需要的信号量数目。比如我们要创建一个信号量,则该值为1.,创建2个就是2   

参数3:sem_flags信号量的创建方式或权限。有IPC_CREAT,IPC_EXCL。
       IPC_CREAT:如果信号量存在,则直接获取,否则申请一个。
       IPC_EXCL:  只有信号量不存在的时候,新的信号量才会创建,否则就产生错误。

 返回值:semget()函数成功返回一个相应信号标识符(非零),失败返回-1.





int semop(int sem_id, struct sembuf *sem_opa, size_t num_sem_ops);
   
作用:改变信号量的值。

参数1:semid信号集的识别码,可通过semget获取。

参数2:sops指向存储信号操作结构的数组指针,信号操作结构的原型如下 
struct sembuf{
       short sem_num; // 除非使用一组信号量,否则它为0
       short sem_op;  // 信号量在一次操作中需要改变的数据,通常是两个数,一个是-1,即P(等待)操作,
               // 一个是+1,即V(发送信号)操作。
        short sem_flg; // 通常为SEM_UNDO,使操作系统跟踪信号,
               // 并在进程没有释放该信号量而终止时,操作系统释放信号量
 };

参数3:num_sem_ops信号操作结构的数量,恒大于或等于1



int semctl(int sem_id, int sem_num, int command, ...);

作用:用来直接控制信号量信息

参数1:信号集的标识符,即是信号表的索引。

参数2:信号集的索引,用来存取信号集内的某个信号。

cmd:需要执行的命令,有效值有

范例

// semget的调用者可以给其key传递一个特殊的键值IPC_PRIVATE(值为0)
// 这样无论信号量是否存在,semget都将创建一个新的信号量。使用该键值
// 创建的信号量
// 并非像它的名字那样是进程私有的。其他进程,尤其子进程,也有办法来访问这个信号量。
// 下面的例子就是在父子进程间使用一个IPC_PRIVATE信号量来进行同步。

#include <sys/sem.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

union semun {
  int val;  // 用于setvalue;
  struct semid_ds* buf;  // 用于ipc_stat 和ipc_set 命令
  unsigned short* array;  // 用于getall 和setall 命令
  struct seminfo* __buf;  // 用于ipc_info命令
};

// op为-1时执行p操作,op为1执行v操作。
// semop操作
void pv( int sem_id, int op) {
  struct sembuf sem_b;
  sem_b.sem_num = 0;  // 信号集中编号为1的信号量
  sem_b.sem_op = op;  // 执行op操作, 大于0,执行+1操作, 小于0 执行-1 操作
  sem_b.sem_flg = SEM_UNDO;  // 信号量操作进程退出时取消正在进行op操作。
  semop(sem_id, &sem_b, 1);  // 操作信号量的个数只有一个
}

int main(int argc, char* argv[]) {

  // 创建一个信号量集,它创建一个新的信号集, 权限为读写
  int sem_id = semget(IPC_PRIVATE, 1, 0666);

  // semctl中第四个参数的格式
  union semun sem_un;
  sem_un.val = 1;

  // SETVAL社会semun.buf的数据成员复制到信号量集关联的内核数据结构中,
  // 同时内核数据中的semid_ds。sem_ctime被更新。
  semctl(sem_id, 0, SETVAL, sem_un);

  // 复制一个新进程
  pid_t pid = fork();

  if (pid < 0) {
    return -1;
  } else if (pid == 0) {
    printf("child try to get binary sem\n");
    // 在父子进程共享IPC_PRIVATE 信号量的关键在于二者都可以操作该信号量的标识符
    // sem_id;
    pv (sem_id, -1);
    printf("child get the sem and would releases it after 20 seconds\n");
    sleep(20);
    pv (sem_id, 1);
    exit(0);
  } else {
    printf("parents try to get binary sem\n");
    pv (sem_id, -1);
    printf("parent get the sem and would releases it after 20 seconds\n");
    sleep(20);
    pv (sem_id, 1);
  }

  waitpid(pid, NULL, 0);
  // 立即移除信号集,唤醒所有等待该信号集的进程
  semctl(sem_id, 0, IPC_RMID, sem_un);

  return 0;
}

注意

1、显示所有的IPC设施
ipcs -a

2、显示所有的消息队列Message Queue

ipcs -q

3、显示所有的信号量

ipcs -s

4、显示所有的共享内存

ipcs -m

5、显示IPC设施的详细信息

ipcs -q -i id

id 对应shmid、semid、msgid等。-q对应设施的类型(队列),查看信号量详细情况使用-s,查看共享内存使用-m。

6、显示IPC设施的限制大小

ipcs -m -l

-m对应设施类型,可选参数包括-q、-m、-s。

7、显示IPC设施的权限关系

ipcs -c

ipcs -m -c

ipcs -q -c

ipcs -s -c

8、显示最近访问过IPC设施的进程ID。

ipcs -p

ipcs -m -p

ipcs -q -p

9、显示IPC设施的最后操作时间

ipcs -t

ipcs -q -t

ipcs -m -t

ipcs -s -t

10、显示IPC设施的当前状态

ipcs -u

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值