1信号量的认知

Linux 中用到的信号量有 3 种:ststem-V 信号量、POSIX 有名信号量和 POSIX 无名信号量)。他们虽然有很多显著不同的地方,但是最基本的功能室一致的:用来表征一种资源的数量,当多个进程或者线程争夺这些稀缺资源的时候,信号量用来保证他们合理地、秩序地使用这些资源,而不会陷入逻辑谬误之中。

用一个例子来说明什么是“旗语”——红绿灯, 一个繁忙的十字路口,稀缺资源就是通过十字路口的权限,为了避免撞车规定每次只能是对开方向的车通过路口不能转弯),此时另外两个方向的车必须停下来等待,直到红绿灯变换为止

一些基本概念如下:

1,多个进程或线程有可能同时访问的资源(变量、链表、文件等等)称为共享资源,也叫临界资源(critical resources)。

2,访问这些资源的代码称为临界代码,这些代码区域称为临界区(critical zone)。

3,程序进入临界区之前必须要对资源进行申请,这个动作被称为 P 操作,这就像你要把车开进停车场之前,先要向保安申请一张停车卡一样,P 操作就是申请资源,如果申请成功,资源数将会减少。如果申请失败,要不在门口等,要不走人。

4,程序离开临界区之后必须要释放相应的资源,这个动作被称为 V 操作,这就像你把车开出停车场之后,要将停车卡归还给保安一样,V 操作就是释放资源,释放资源就是让资源数增加。所有一起访问共同临界资源的进程都必须遵循以上游戏规则,否则大家就都乱套了,但是值得注意的是:这些规则是自愿的,如果有进程就是胡来——在访问资源之前不申请,那么将会可能导致逻辑谬误,就像开车压死保安直接撞进停车场一样,虽然于情于理都不可以,物理上阻止不了这种行为。

2相关API

创建信号量时,还受到以下系统信息的影响:
        1,SEMMNI:系统中信号量的总数最大值。
        2,SEMMSL:每个信号量中信号量元素的个数最大值。
        3,SEMMNS:系统中所有信号量中的信号量元素的总数最大值。
        Linux 中,以上信息在/proc/sys/kernel/sem 中可查看。

使用以上函数接口需要注意以下几点:
        1,信号量操作结构体的定义如下:

struct sembuf{unsigned short sem_num; /* 信号量元素序号(数组下标) */short sem_op; /* 操作参数 */short sem_flg; /* 操作选项 */};

请注意:信号量元素的序号从 0 开始,实际上就是数组下标。
        2,根据 sem_op 的数值,信号量操作分成 3 种情况:
        A) 当 sem_op 大于 0 时:进行 V 操作,即信号量元素的值(semval)将会被加上 sem_op 的值。如果 SEM_UNDO 被设置了,那么该 V 操作将会被系统记录。V 操作永远不会导致进程阻塞。
        B) 当sem_op等于0时:进行等零操作,如果此时semval恰好为0,则semop( )立即成功返回,否则如果 IPC_NOWAIT 被设置,则立即出错返回并将 errno 设置为EAGAIN,否则将使得进程进入睡眠,直到以下情况发生:

B1) semval 变为 0。
                B2) 信号量被删除。(将导致 semop( )出错退出,错误码为 EIDRM)
                B3) 收到信号。(将导致 semop( )出错退出,错误码为 EINTR)
        C) 当 sem_op 小于 0 时:进行 P 操作,即信号量元素的值(semval)将会被减去 sem_op 的绝对值。如果 semval 大于或等于 sem_op 的绝对值,则 semop( )立即成功返回,semval 的值将减去 sem_op 的绝对值,并且如果 SEM_UNDO 被设置了,那么该 P 操作将会被系统记录。如果 semval 小于 sem_op 的绝对值并且设置了IPC_NOWAIT,那么 semop( )将会出错返回且将错误码置为 EAGAIN,否则将使得进程进入睡眠,直到以下情况发生:
                C1) semval 的值变得大于或者等于 sem_op 的绝对值。

C2) 信号量被删除。(将导致 semop( )出错退出,错误码为 EIDRM

C3) 收到信号。(将导致 semop( )出错退出,错误码为 EINTR)

3代码展示

sem_p.c(进行减操作)

#include #include #include #include #include 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) */           };int main(void){  key_t key;  int sem_id;  int retval;  //获取一个IPC对象  key = ftok(".", 1);  if(key == -1)  {    perror("获取IPC对象的key值出错");    goto get_ipc_key_err;  }  //获得信号量ID,其中如果信号量没有则创建出来,1代表创建1个信号量  sem_id = semget( key, 1, IPC_CREAT|0644);  if(sem_id == -1)  {    perror("获取信号量出错");    goto get_semid_err;  }  union semun semarg;//这个是semctl函数说明的,如果第四个参数需要定义的一个共用体  semarg.val = 0;//设置信号量初值为0  /*    设置信号量初值    sem_id:设置的信号量ID    0:设置这个信号量当中的第几个信号量    SETVAL:命令,设置单个信号量的初值    semarg:设置的共用体  */  semctl(sem_id, 0, SETVAL, semarg);  struct sembuf op_sem;  op_sem.sem_num = 0;//第几个信号量  op_sem.sem_op = -1;//-1操作  op_sem.sem_flg = 0;//按照默认的信号量操作(当减到即将成为一个负数的时候陷入睡眠)  //进行减操作  /*    sem_id:操作的信号量    op_sem:做何种操作    1:一次性操作1个信号量  */  semop( sem_id, &op_sem, 1);    printf("减操作成功\n");    //删除整个信号量集合  //semctl(sem_id, 0, IPC_RMID);  return 0;get_semid_err:get_ipc_key_err:  return -1;}

sem_v.c(进行加操作)

#include #include #include #include #include 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) */           };int main(void){  key_t key;  int sem_id;  int retval;  //获取一个IPC对象  key = ftok(".", 1);  if(key == -1)  {    perror("获取IPC对象的key值出错");    goto get_ipc_key_err;  }  //获得信号量ID,其中如果信号量没有则创建出来,1代表创建1个信号量  sem_id = semget( key, 1, IPC_CREAT|0644);  if(sem_id == -1)  {    perror("获取信号量出错");    goto get_semid_err;  }  struct sembuf op_sem;  op_sem.sem_num = 0;//第几个信号量  op_sem.sem_op = 1;//+1操作  op_sem.sem_flg = 0;//按照默认的信号量操作(当减到即将成为一个负数的时候陷入睡眠)  //进行加操作  /*    sem_id:操作的信号量    op_sem:做何种操作    1:一次性操作1个信号量  */  semop( sem_id, &op_sem, 1);    //删除整个信号量集合  //semctl(sem_id, 0, IPC_RMID);  return 0;get_semid_err:get_ipc_key_err:  return -1;}

记录点点滴滴的笔记欢迎关注,共同学习

小浩笔记

linux 信号量_SystemV IPC通信信号量相关推荐

  1. python并发编程之semaphore(信号量)_python 之 并发编程(守护进程、互斥锁、IPC通信机制)...

    9.5 守护进程 主进程创建守护进程 其一:守护进程会在主进程代码执行结束后就立即终止 其二:守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemonic process ...

  2. Linux进程间通信第四讲 标准IPC之信号量集

    目录 4.3信号量集 4.3.1 概念和原理 4.3.2 使用 4.3信号量集 4.3.1 概念和原理 (不是用于进程间传递数据.而是用于进程间访问控制) 信号量集是一个信号量的集合,可以存放多个信号 ...

  3. linux进程间通信:system V 信号量 生产者和消费者模型编程案例

    生产者和消费者模型: 有若干个缓冲区,生产者不断向里填数据,消费者不断从中取数据 两者不冲突的前提: 缓冲区有若干个,且是固定大小,生产者和消费者各有若干个 生产者向缓冲区中填数据前需要判断缓冲区是否 ...

  4. linux 内核信号量与用户态信号量(system v,信号量在Linux多线程机制中的应用

    [摘 要]本文以信号量原理为基础,重点阐述信号量在Linux多线程同步机制中的实现特色. [关键词]信号量:Linux:多线程:同步 1 信号量 1965年E. W. Dijkstra首次提出信号量的 ...

  5. 深刻理解 Linux 进程间七大通信(IPC)

    前言 网络编程是 Linux C/C++的面试重点,今天我就来聊一聊进程间通信的问题,文章末尾列出了参考资料,希望帮助到大家. 篇幅有点长,希望大家耐心阅读. Linux 下的进程通信手段基本上是从 ...

  6. linux进程间通信:system V 信号量

    文章目录 概念描述 通信原理 编程接口 使用流程 编程案例 概念描述 英文:semaphore 简称SEM,主要用来进行进程间同步 本质:内核维护的一个正整数,可对其进行各种+/-操作 分类:syst ...

  7. 专题 13 IPC之信号量

    1.概述 信号量是一种计数器,用来控制对多个进程共享的资源所进行的访问.它们常被用做一个锁机制. 2.相关数据结构与函数 信号量数据结构: structsemun { intval;//当执行SETV ...

  8. Linux进程间通信三 System V 信号量简介与示例

    1. System V信号量简介 SystemV信号量主要用于解决生产者和消费者问题,一个信号量能够控制多个资源,说它是信号量集也不为过. 2. API接口介绍 2.1 创建或打开信号量集 #incl ...

  9. Linux内核信号量:二值信号量/互斥信号量,计数信号量,读写信号量

    <semaphore信号量:一个简单的示例程序>用户态程序 目录 概念 应用场景 使用方法 内核信号量的构成 信号量的API 初始化 PV操作 获取信号量(P) 释放内核信号量(V) 补充 ...

  10. Linux下多线程编程中信号量介绍及简单使用

    在Linux中有两种方法用于处理线程同步:信号量和互斥量. 线程的信号量是一种特殊的变量,它可以被增加或减少,但对其的关键访问被保证是原子操作.如果一个程序中有多个线程试图改变一个信号量的值,系统将保 ...

最新文章

  1. A - 排名 HDU - 1236 sort(cmp)
  2. If-Modified-Since和If-None-Match
  3. 反浏览器指纹追踪(反浏览器指纹追踪技术)
  4. 嵌入式开发概述(树莓派介绍)
  5. 编写函数判断一个数是否是回文数_程序员面试金典 - 面试题 01.04. 回文排列
  6. python多目标优化_多目标优化算法(四)NSGA3(NSGAIII)论文复现以及matlab和python的代码...
  7. 一文初探Tensorflow高级API使用(初学者篇)
  8. Linux 文件传输
  9. linux系统启动后卡在笑脸符号,【转】Linux中的特殊符号
  10. 光影精灵usb安装linux,惠普光影精灵5笔记本怎么装win10系统(uefi+gpt)
  11. DES 加密解密方法
  12. 阿里云ecs服务器买完后可以更换操作系统么?
  13. vscode编译Window c++程序缺少vc运行库解决方法
  14. # CF #808 Div.2(A - C)
  15. CAS单点登录(SSO)介绍及部署
  16. 面向过程、面向对象 的模型和方法
  17. java roll_Java Calendar roll()用法及代碼示例
  18. Chrome 超强生产力工具 Omni
  19. 上海迪士尼度假区将推出一系列节庆活动和全新“萌聚达菲月”
  20. 从《羞羞的铁拳》中嗅到的

热门文章

  1. git pull冲突:commit your changes or stash them before you can merge.
  2. ubuntu备份与恢复
  3. android sid如何验证有效性,使用RMAN验证备份的有效性
  4. Docker 快速安装教程
  5. springcloud之eureka集群搭建
  6. servlet 之forward和sendRedirect跳转
  7. JavaScript编写计算器-《JavaScript王者归来》读书笔记1
  8. C++ 数组动态分配
  9. 携程基于云的软呼叫中心及客服平台架构实践\n
  10. Android UsageStatsService(应用使用统计服务)的学习与调研