进程间通信方式---信号量

1、概念

为了防止出现因多个程序同时访问一个共享资源而引发的一系列问题,我们需要一种方法,它可以通过生成并使用令牌来授权,在任一时刻只能有一个执行线程访问代码的临界区域。临界区域是指执行数据更新的代码需要独占式地执行。而信号量就可以提供这样的一种访问机制,让一个临界区同一时间只有一个线程在访问它,也就是说信号量是用来调协进程对共享资源的访问的。

信号量是一个特殊的变量,程序对其访问都是原子操作,且只允许对它进行等待(即P(信号变量))和发送(即V(信号变量))信息操作。最简单的信号量是只能取0和1的变量,这也是信号量最常见的一种形式,叫做二进制信号量。而可以取多个正整数的信号量被称为通用信号量。

2、工作原理

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

举个例子,就是两个进程共享信号量sv,一旦其中一个进程执行了P(sv)操作,它将得到信号量,并可以进入临界区,使sv减1。而第二个进程将被阻止进入临界区,因为当它试图执行P(sv)时,sv为0,它会被挂起以等待第一个进程离开临界区域并执行V(sv)释放信号量,这时第二个进程就可以恢复执行。

注:为了获得共享资源,进程需要执行下列操作:

(1)测试控制该资源的信号量。

(2)若此信号量的值为正,则进程可以使用该资源。进程将信号量值减1,表示它使用了一个资源单位。

(3)若此信号量的值为0,则进程进人休眠状态,直至信号量值大于0。进程被唤醒后,它返回至第(1)步。

当进程不再使用由一个信号量控制的共享资源时,该信号量值增1。如果有进程正在休眠等待此信号量,则唤醒它们。

为了正确地实现信号量,信号量值的测试及减1操作应当是原子操作。为此,信号量通常是在内核中实现的。

常用的信号量形式被称为二元信号量或双态信号量(binary semaphore)。它控制单个资源,初始值为1。但是一般而言,信号量的初值可以是任一正值,该值说明有多少个共享资源单位可供共享应用。

3、Linux信号量机制

3.1  semeget函数

它的作用创建一个新的信号量或者取得一个已有信号量。原型如下:

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

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

第二个参数num_sems指定需要的信号量数目,它的值几乎总是1。

第三个参数sem_flags是一组标志,当想要当信号量不存在时创建一个新的信号量,可以和值IPC_CREAT做按位或操作。设置了IPC_CREAT标志后,即使给出的键是一个已有信号量的键,也不会产生错误。而IPC_CREAT | IPC_EXCL则可以创建一个新的,唯一的信号量,如果信号量已存在,返回一个错误。

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

3.2  semop函数

它的作用是改变信号量的值 ,原型为:

int semop(int sem_id, sembuf *semopa, size_t num_sem_ops);

sem_id是由semget返回的信号量标识符,sembuf结构的定义如下:


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

3.3  semctl函数

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semctl(int semid, int semun, int cmd, ...);
  • 用来初始化信号集,或者删除信号集。
  • semid:信号量集I P C 标识符。
  • semun:操作信号在信号集中的编号,第一个信号的号是0.
  • cmd:在semid指定的信号量集合上执行此命令。
  • 第四个参数是可选的,如果使用该参数,则其类型是semun,它是多个特定命令参数的联合(union):
union semun
{int val;    struct semid_ds * buf;unsigned short * array;struct seminfo * __buf;
};
  • 第三个参数cmd常用命令:
  • IPC_SEAT:对此集合取semid_ds 结构,并存放在由arg.buf指向的结构中。
  • IPC_RMID:从系统中删除该信号量集合。
  • SETVAL:设置信号量集中的一个单独的信号量的值,此时需要传入第四个参数。
  • 返回值:成功返回一个正数,失败返回-1。

4、信号量相关背景知识

4.1  原子操作(atomic operation)

原子操作意为不可被中断的一个或一系列操作,也可以理解为就是一件事情要么做了,要么没做。而原子操作的实现,一般是依靠硬件来实现的。

4.2  同步与互斥

同步:在访问资源的时候,以某种特定顺序的方式去访问资源 
       互斥:一个资源每次只能被一个进程所访问。

同步与互斥是保证在高效率运行的同时,可以正确运行。大部分情况下同步是在互斥的基础上进行的。

4.3  临界资源

各个进程采取互斥的方式,实现共享的资源称作临界资源。属于临界资源的硬件有打印机、磁带机等。软件有消息缓冲队列、变量、数组、缓冲区等。诸进程间应采取互斥方式,实现对这种资源的共享。

4.4  临界区

每个进程中访问临界资源的那段代码称作临界区。显然若能保证诸进程互斥的进入自己的临界区,便可实现诸进程对临界资源的互斥访问。为此,每个进程在进入临界区之前,应先对欲访问的临界资源进行检查,看他是否正在被访问,如果此刻该临界资源未被访问,进程便可进入临界区对临界资源进行访问,并设置它正被访问标志;如果此刻该临界资源正被访问,则本进程不能进入临界区。

*  在操作系统中,有临界区的概念。临界区内放的一般是被一个以上的进程或线程共用的数据。

          *  临界区的数据依次只能同时被一个进程访问,当一个进程使用临界区的数据时,其他需要使用临界区的数据的进程进入等待状态。

          *  操作系统需合理的分配临界区以到达多进程的同步和互斥,如果协调不好,就容易使系统不安全,甚至出现死锁。

【 Linux 】进程间通信之信号量相关推荐

  1. Linux进程间通信(信号量)

    ★什么是信号量 为了防止出现多个程序同时访问一个共享数据资源而引发的问题,需要一种方法,它可以通过生成并使用令牌来授权,在任一时刻只能有一个执行线程访问代码的临界区.信号量就可以提供这样一种访问机制. ...

  2. Linux 进程间通信之 - 信号量

    前言 很久不用,基本概念虽然还记得,估计不会用了,写个demo练练手. 概念 信号量(信号灯)本质上是一个计数器,用于协调多个进程(包括但不限于父子进程)对共享数据对象的读/写.它不以传送数据为目的, ...

  3. Linux进程间通信——使用共享内存

    下面将讲解进程间通信的另一种方式,使用共享内存. 一.什么是共享内存 顾名思义,共享内存就是允许两个不相关的进程访问同一个逻辑内存.共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式 ...

  4. Linux多线程——使用信号量同步线程

    http://blog.csdn.net/ljianhui/article/details/10813469/ 信号量.同步这些名词在进程间通信时就已经说过,在这里它们的意思是相同的,只不过是同步的对 ...

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

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

  6. Linux进程间通信--进程,信号,管道,消息队列,信号量,共享内存

    Linux进程间通信--进程,信号,管道,消息队列,信号量,共享内存 参考:<linux编程从入门到精通>,<Linux C程序设计大全>,<unix环境高级编程> ...

  7. Linux进程间通信(管道、消息队列、共享内存、信号、信号量)

    目录 Linux进程间通信概述 1.管道 无名管道(pipe) 有名管道(fifo) 2.消息队列(msg) 消息队列的通信原理 消息队列相关api 消息队列收发数据 键值生成 消息队列移除 3.共享 ...

  8. linux进程间通信:POSIX 共享内存

    文章目录 思维导图 通信原理 优势 POSIX 共享内存 编程接口 编程案例 思维导图 之前学习过sysemV 的共享内存的实现及使用原理,参考linux进程间通信:system V 共享内存 POS ...

  9. Linux进程间通信(二):信号集函数 sigemptyset()、sigprocmask()、sigpending()、sigsuspend()...

    我们已经知道,我们可以通过信号来终止进程,也可以通过信号来在进程间进行通信,程序也可以通过指定信号的关联处理函数来改变信号的默认处理方式,也可以屏蔽某些信号,使其不能传递给进程.那么我们应该如何设定我 ...

最新文章

  1. mac 用 brew
  2. POJ 3660 Cow ContestCow(Floyd传递闭包)题解
  3. Facebook力推导航库:React Navigation使用详解
  4. 【离散数学中的数据结构与算法】二 欧几里得算法与裴蜀等式
  5. 浏览器怪异模式和标准模式之间的区别 DTD
  6. 考计算机科学考研老师问,名师答疑:计算机专业考研复习6问!
  7. 固态硬盘(samsung SSD 850 pro)相关问题
  8. 在线制作证件照教程,只需30秒
  9. 发光二极管工作电流分析
  10. DeepFool(迷惑深度学习分类模型)测试
  11. quartus II 9.1的sof和elf 文件合并成JIC文件
  12. IDEA中使用UT测试过程中的一些小问题
  13. 我的完整版mbti职业性格测试
  14. 软件测试:三角形问题
  15. 如何处理json数据
  16. eclipse一次性开启多个工程
  17. C语言 malloc calloc realloc
  18. 华为LiteOS操作系统基础知识入门与内核移植
  19. mysql+优化器+软解析_MySQL执行计划 - osc_93u9qofu的个人空间 - OSCHINA - 中文开源技术交流社区...
  20. PageHelper 补充

热门文章

  1. Conditional Independent Assumption 條件獨立假設
  2. 学计算机的女生最后都怎么样了?
  3. supervisord 后台管理工具
  4. 《Kotlin 极简教程 》第4章 基本数据类型与类型系统
  5. 【数据库系统】数据库安全性控制
  6. uCOS-II 基础入门教程(一)
  7. hover 鼠标悬浮改变样式
  8. Metric的快速入门
  9. Moveit编程——moveit 编程技巧笔记——圆弧轨迹规划+修改轨迹
  10. 高德地图轨迹展示样式修改