概念

1、临界资源:同一时刻,只允许一个或有限个进程或线程访问的资源。
例如:
(1)多个人同时用一个笔签字,此时只能有一个人用笔写字,其他人只有等他写完才可以使用这支笔。
(2)若商场试衣间可以有3个试衣间,可以同时供3个人使用,其他人必须等到其中的试衣间没人才能使用。
(3)但是像走廊,不是临界资源,可以同时由多人同时通行。
2、临界区:访问临界资源的代码段。
3、原子操作:不可被分割或中断的操作,操作一旦开始执行,就比执行结束,中途不能被任何原因打断。

例:1:

i = 0;
i++;

当只有一个线程执行这块代码时,执行结束后i的值是1。而如果有两个线程同时执行这块代码时,我们期望的结果是i的值最后变成2。但由于这两句不是原子操作。如果有一个线程还没来得及将修改之后i的值写回内存,而被打断了,这时别的线程就会从内存中读取到原有的值,这两个线程可能同时拿到的i的值为0,等两个线程执行完,i的值不是2而是1。
所谓的原子操作,就是要保证一个线程将i的值修改完之后的结果先写回内存中,然后另一个线程才能访问这个变量,这时线程拿到的值才是正确的。

例2:还有像火车买票过程就是多线程访问票数这个临界资源,必须保证一个线程修改票数的时候,其他线程不能访问,否则就会出现本来已经没票了,却多卖出了一些票的结果。

4、信号量类似于计数器,是一个特殊的变量,值可以改变,但只能取正整数值,并且对它的加1和减1操作是原子操作。如果信号量值为0,那么再进行减1操作时会阻塞。信号量的初始值,代表资源的数量。
作用:控制多个进程对临界资源的访问,使程序在同一个时刻,只有一个进程访问临界资源(进行进程间同步控制)。原理就是控制程序的执行速度。
进程间同步控制:
(1)同步执行:两个或多个进程需要协同执行,进程A的执行需要进程B提供支持
(2)异步执行:进程A和进程B互不干扰,在B给A发送数据前,A不会等待数据到达。
只有B给A发送数据后,A去处理数据。(类似信号)
例1:
多个人要去饮水机接热水,先到先得,其他人需要先等待,直到没人使用,才可以轮到自己。但是要让程序实现等这个操作就比较麻烦,所以可以通过信号量来控制。
例2:
十字路口的红绿灯其实就是起到了信号量的作用,它控制了车辆的行进速度,才能保证中间的那块区域(临界资源)是安全和持续可用的。

信号量的操作

1、创建:semget函数
函数原型:int semget(key_t key, int num_sems:, int sem_flags);
作用:第一次使用时创建信号量,以后使用时获取信号量。
参数:
key:一个整型值对应内核中一个信号量对象,可以自己指定,不同信号量的key值不一样。不相关的进程可以通过它访问同一个信号量。程序对所有信号量的访问都是间接的,它先提供一个键,再由系统生成一个响应的信号标识符。
num_sems:信号量的数目。
sem_flags:设置一组标志,与open函数的标志非常相似,包括信号量的权限等。IPC_CREAT标志是创建或者使用已有的信号量。
而IPC_CREATE和IPC_EXCL结合使用可以确保创建出的是一个新的、唯一的信号量,如果该信号量已存在,它将返回一个错误。
创建时给出的权限可以是:0600。
2、初始化、删除 :semctl(cmd)
作用:对信号量值进行修改。
函数原型:int semctl(int sem_id, int sem_num, int command, ...);
sem_id:信号量id。
sem_num:信号量的下标,从0开始。
command:具体的操作命令,有SETVAL(设置初值)、IPC_RMID(移除信号量)
最后一个参数可以有也可以没有,如果有的话。它将会是一个union semun结构,包含以下几个成员:

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

一般只使用val这个成员,来为信号量赋初值。当信号量值为0时,进程会阻塞运行。
3、具体操作
+1 V操作 semop
-1 P操作 semop
P V操作是原子操作
函数原型:int semop(int sem_id, struct sembuf *sem_ops,size_t num_sem_ops);
sem_id:信号量的id,用作标识。
sem_ops:指向一个结果体数组的指针,每个数组元素至少包含以下几个成员:

struct sembuf
{short sem_num;short sem_op;short sem_flg;
}

sem_num是信号量的下标,sem_op是信号量一次操作总需要改变的数值,+1是v操作,-1是p操作,sem_flg通常设置为SEM_UNDO,表示操作系统会跟踪当前进程对这个信号量的修改情况,如果这个进程在没有释放该信号量的情况下终止,操作系统将自动释放该进程持有的信号量,防止其他进程一直处于等待状态。
num_sem_ops:指的是结构数组的元素个数。

4、信号量的命令操作
查看:ipcs -s
删除:ipcrm -s semid
semid指的是信号量的id,可以同过查看命令看到。

注意:
(1)内核对象和键值对:
内核对象:系统内核中,创建、控制和销毁的一个对象或变量。
键值对:key-value,通过key获取值。

(2)可以封装信号的操作

sem_get();  //获取信号量
sem_p();    //-1操作
sem_v();    //+1操作
sem_del();  //删除操作

具体实现:
sem.h

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/sem.h>
#include <unistd.h>struct semun
{int val;
};void sem_init();void sem_p();void sem_v();void sem_destroy();

sem.c

#include "sem.h"static int semid = 0;void sem_init()
{semid = semget((key_t)1234,1,IPC_CREAT | IPC_EXCL| 0600);if(semid == -1){semid = semget((key_t)1234,1,IPC_CREAT | 0600);if(semid == -1){printf("semget error");}}else{union semun a;//a传值a.val = 1;if(semctl(semid,0,SETVAL,a)==-1)//0代表信号量下表{perror("semctl init error");}}
}void sem_p()
{struct sembuf buf;buf.sem_num = 0;//信号量下标buf.sem_op = -1;//p操作buf.sem_flg = SEM_UNDO;if(semop(semid,&buf,1)==-1){perror("p error");}
}void sem_v()
{struct sembuf buf;buf.sem_num = 0;buf.sem_op = 1;buf.sem_flg = SEM_UNDO;//设置在进程出现错误时信号量值自动恢复,防止一个进程占着信号量if(semop(semid,&buf,1)==-1)//1表示操作数,sembuf的数量{perror("v error");}
}void sem_destroy()
{if(semctl(semid,0,IPC_RMID)==-1)//0代表信号量集{perror("semctl destroy error");}
}

信号量的使用举例

例1:模拟对打印机的使用,同一时刻只能一个人打印,printf代表打印,打印a开始,打印第二个a结束打印,打印a时不能打印b,可以出现4个a或4个b的情况,不能出现交错打印的情况。

思路:a先访问打印机时,b中的p操作阻塞住,当a执行完,进行v操作,b执行p操作,此时a中的p操作阻塞,当b执行完,执行v操作,a中的p操作就不会阻塞。
代码:
a.c

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include "sem.h"int main()
{sem_init();int i = 0;for(;i<10;++i){sem_p();printf("A");fflush(stdout);int n = rand()%3;sleep(n);printf("A");fflush(stdout);sem_v();n = rand()%3;sleep(n);}
}

b.c

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include "sem.h"int main()
{sem_init();int i = 0;for(;i<10;++i){sem_p();printf("B");fflush(stdout);int n = rand()%3;sleep(n);printf("B");fflush(stdout);sem_v();n = rand()%3;//产生随机睡眠时间sleep(n);}sleep(10);sem_destroy();
}

输出结果:

Linux进程间通信(二)之信号量相关推荐

  1. linux进程间通信:POSIX信号量

    文章目录 概念描述 编程接口 注意事项 编程案例 信号量基本接口使用案例 信号量父子进程间通信 信号量实现 两进程之间通信 概念描述 英文:semaphore 简称SEM,主要用来进行进程间同步 本质 ...

  2. Linux进程间通信五 Posix 信号量简介与示例

    1. 信号量简介 信号量用于进程或线程间同步,Posix信号量是一个非负整型,只有两种操作,加一(sem_post)和减一(sem_wait),如果信号量值为0,sem_wait默认阻塞. Posix ...

  3. Linux进程间通信二 System V 消息队列简介与示例

    1. SystemV消息队列简介 消息队列,顾名思义即是存放消息的队列,内核为每个SystemV 维护了一个msg_queue的结构体,里面记录了每个消息队列的信息. struct msg_queue ...

  4. Linux系统无名管道通信实验,Linux进程间通信(二)---管道通信之无名管道及其基础实验...

    管道简介 管道是Linux中进程间通信的一种方式,它把一个程序的输出直接连接到另一个程序的输入(其实我更愿意将管道比喻为农村浇地的管子).Linux的管道主要包括两种:无名管道和有名管道.这一节主要讲 ...

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

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

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

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

  7. Linux IPC进程间通信(三):信号量

    系列文章: Linux IPC进程间通信(一):管道 Linux IPC进程间通信(二):共享内存 Linux IPC进程间通信(三):信号量 Linux IPC进程间通信(四):消息队列 文章目录 ...

  8. Linux进程间通信—信号量

    二.信号量(semophore) 信号量是一种计数器,可以控制进程间多个线程或者多个进程对资源的同步访问,它常实现为一种锁机制.实质上,信号量是一个被保护的变量,并且只能通过初始化和两个标准的原子操作 ...

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

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

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

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

最新文章

  1. 硅谷顶级VC发声:AI技术公司毛利实在太低,人工和算力成本太高
  2. 洛谷 P1985 翻转棋
  3. VLAN配置命令列表
  4. MySQL数据类型及范围用法一览表
  5. Python基础(十一)--正则表达式
  6. mysql devel 编译_mysql编译安装
  7. php隔行符,PHP PHP_EOL 换行符
  8. EL表达式判断条件要写在${}内
  9. uoj #298. 【CTSC2017】网络
  10. SharePoint 2010 大局观(1~3)
  11. 获取服务器响应失效,从Web服务器获取响应时出现问题
  12. 视频编码中CBR编码和VBR编码的区别
  13. Vuforia Vumark初探
  14. 一文揭开图机器学习的面纱,你确定不来看看吗
  15. U盘只能读,不能写,不能删,也不能格式化的处理
  16. android hook 第三方app_【MiSRC】技术分享-浅谈android hook技术
  17. SpringBoot框架的基本结构
  18. 基于ubuntu系统的HEVC视频编码与解码
  19. STM32基础10--实时时钟(RTC)
  20. python正负数排序_带有负值的Python sort()问题

热门文章

  1. tp5.0 think-queue 消息队列
  2. linux 查看已安装软件
  3. 未来科学技十幻想画计算机,人教版美术教案第七册(全册)
  4. 视频文案合并,清除原视频声音让文案转语音
  5. 百度AI攻略:手写文字识别
  6. 苹果/安卓兼容性页面显示问题
  7. Torch7系列教程之Torch深度学习库教程(一)
  8. 如何快速上手操作Mac电脑?新手问号
  9. 解决nasm汇编gdb无法单步调试
  10. 博凌科技携手中企动力用互联网思维卖乐器