信号量的本质是一种数据操作锁,它本身不具有数据交换的功能,而是通过控制其他的
通信资源(文件,外部设备)来实现进程间通信,它本身只是一种外部资源的标识。信号
量在此过程中负责数据操作的互斥、同步等功能。
    当请求一个使用信号量来表示的资源时,进程需要先读取信号量的值来判断资源是否可
用。大于0,资源可以请求,等于0,无资源可用,进程会进入睡眠状态直至资源可用。
  当进程不再使用一个信号量控制的共享资源时,信号量的值+1,对信号量的值进行的增减
操作均为原子操作,这是由于信号量主要的作用是维护资源的互斥或多进程的同步访问。
而在信号量的创建及初始化上,不能保证操作均为原子性。

一. 为什么要使用信号量?

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

二. 信号量的工作原理
由于信号量只能进行两种操作等待和发送信号,即P(sv)和V(sv),他们的行为是这样的:
P(sv):如果sv的值等于零,就给它减1;如果它的值为零,就挂起该进程的执行
V(sv):如果有其他进程因等待sv而被挂起,就让它恢复运行,如果没有进程因等待sv而挂
起,就给它加1. 
  
举个例子,就是两个进程共享信号量sv,一旦其中一个进程执行了P(sv)操作,它将得到信号
量,并可以进入临界区,使sv减1。而第二个进程将阻止进入临界区,因为当它试图执行
P(sv)时,sv为0,它会被挂起以等待第一个进程离开临界区域并执行V(sv)释放信号量,这时
第二个进程就可以恢复执行。

三 .Linux的信号量机制
Linux提供了一组精心设计的信号量接口来对信号量进行操作,它们不只是针对二进制信号
量,下面将会对这些函数进行介绍,但请注意,这些函数都是用来对成组的信号量值进行
操作的。它们声明在头文件sys/sem.h中。

信号量的意图在于进程间同步,互斥锁和条件变量的意图则在于线程间同步。但是信号
量也可用于线程间,互斥锁和条件变量也可用于进程间。我们应该使用适合具体应用的那
组原语。

简易的信号量实现:

comm.h

#ifndef _COMM_H_
#define _COMM_H_
#include<sys/sem.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#define PATHNAME "."
#define PROJ_ID "0x6666"typedef struct mysembuf
{unsigned short int sem_num; /* semaphore number */short int sem_op;  /* semaphore operation */short int sem_flg;  /* operation flag */
}mysembuf;typedef union semun
{int val;struct semid_ds *buf;unsigned short *array;struct seminfo*_buf;
}_semnu;int creat_sems(int nums);
int get_sems();
int init_sems(int semid,int which);
int destory_sem(int semid);
int P(int semid,int which);
int V(int semid,int which);#endif

comm.c

#include"comm.h"static int comm_sems(int nums,int flags)
{key_t k = ftok(PATHNAME,PROJ_ID);int semid=semget(k,nums,flags);if(semid<0){perror("semget");}return semid;}int creat_sems(int nums)
{return comm_sems(nums,IPC_CREAT|IPC_EXCL|0666);
}int get_sems()
{return comm_sems(0,IPC_CREAT);
}int init_sems(int semid,int which)
{_semnu __semun;__semun.val=1;if(semctl(semid,which,SETVAL,__semun)<0){perror("semctl");return -1;}return 0;
}int destory_sem(int semid)
{if(semctl(semid,0,IPC_RMID,NULL)<0){return -1;}return 0;
}static int comm_op(int semid,int which,int op)
{struct mysembuf sbuf;
//  memset();sbuf.sem_op=op;sbuf.sem_flg=0;sbuf.sem_num=which;return semop(semid,&sbuf,1);
}int P(int semid,int which)
{return comm_op(semid,which,-1);
}
int V(int semid,int which)
{return comm_op(semid,which,1);
}
#include"comm.h"int main()
{int semid=creat_sems(1);init_sems(semid,0);pid_t id=fork();if(id<0){perror("fork");}if(id==0){//childwhile(1){int _semid=get_sems();P(_semid,0);printf("A");usleep(12345);fflush(stdout);printf("A");usleep(35412);fflush(stdout);V(_semid,0);}}else{//fatherwhile(1){P(semid,0);printf("B");usleep(32345);fflush(stdout);printf("B");usleep(28712);fflush(stdout);V(semid,0);}wait(NULL);desrory_sems(semid);}return 0;
}

当操作信号量(semop)时,sem_flg可以设置SEM_UNDO标识;SEM_UNDO用于将修改的信号量值在进程正常退出(调用exit退出或main执行完)或异常退出(如段异常、除0异常、收到KILL信号等)时归还给信号量。

如信号量初始值是20,进程以SEM_UNDO方式操作信号量减2,减5,加1;在进程未退出时,信号量变成20-2-5+1=14;在进程退出时,将修改的值归还给信号量,信号量变成14+2+5-1=20。

对linux信号量的理解以及实现相关推荐

  1. linux信号量的理解及使用

    信号量是一个计数器.可以用于多进程也可以用于多线程,主要用于共享数据的同步访问. 如果受保护的资源是可用的,那么信号量的值为正数,如果受保护的资源现在不可用,那么信号量的值为0. 请求访问保护资源(P ...

  2. 查询linux信号量命令,linux下的trap命令和SIGHUP信号量详解。

    19) SIGSTOP 停止(stopped)进程的执行. 注意它和terminate以及interrupt的区别: 该进程还未结束, 只是暂停执行. 本信号不能被阻塞, 处理或忽略. 20) SIG ...

  3. Linux内核深入理解定时器和时间管理(7):相关的系统调用

    Linux内核深入理解定时器和时间管理 相关的系统调用 rtoax 2021年3月 在原文基础上,增加5.10.13内核源码相关内容. 结构体 ---------------------------- ...

  4. Linux内核深入理解定时器和时间管理(5):clockevents 框架

    Linux内核深入理解定时器和时间管理 clockevents 框架 rtoax 2021年3月 在原文基础上,增加5.10.13内核源码相关内容. 1. Introduction to the cl ...

  5. Linux内核深入理解定时器和时间管理(4):定时器 timer

    Linux内核深入理解定时器和时间管理 定时器 timer rtoax 2021年3月 在原文基础上,增加5.10.13内核源码相关内容. 1. Timers This is fourth part ...

  6. Linux内核深入理解定时器和时间管理(3):tick 广播 框架 和 dyntick

    Linux内核深入理解定时器和时间管理 tick 广播 框架 和 dyntick rtoax 2021年3月 在原文基础上,增加5.10.13内核源码相关内容. 结构体 --------------- ...

  7. Linux内核深入理解定时器和时间管理(2):clocksource 框架

    Linux内核深入理解定时器和时间管理 clocksource 框架 rtoax 2021年3月 在原文基础上,增加5.10.13内核源码相关内容. 全局部变量 ------------------- ...

  8. Linux内核深入理解定时器和时间管理(1):硬件时钟和jiffies

    Linux内核深入理解定时器和时间管理 硬件时钟和jiffies rtoax 2021年3月 在原文基础上,增加5.10.13内核源码相关内容. 全局部变量 --------------------- ...

  9. Linux内核深入理解系统调用(3):open 系统调用实现以及资源限制(setrlimit/getrlimit/prlimit)

    Linux内核深入理解系统调用(3) open 系统调用实现以及资源限制(setrlimit/getrlimit/prlimit) rtoax 2021年3月 对原文进行了5.10.13的代码分析. ...

  10. Linux内核深入理解系统调用(2):vsyscall 和 vDSO 以及程序是如何运行的(execve)

    Linux内核深入理解系统调用(2) vsyscall 和 vDSO 以及程序是如何运行的(execve) rtoax 2021年3月 1. vsyscalls 和 vDSO 这是讲解 Linux 内 ...

最新文章

  1. 空指针错误 java.lang.NullPointerException 浅谈
  2. 在继承中派生类成员的访问权限测试
  3. java虚拟键盘_web虚拟键盘VirtualKeyboard
  4. layui登录页面写入数据_layui 页面保存数据
  5. 侧输出流简单应用-打印的完整流程
  6. day8网络编程,面向对象1
  7. C# 如何修改Form不能修改窗体大小
  8. Airbnb搜索:深度学习排序算法如何进化?
  9. 普罗米修斯 感染组合表
  10. 关于计算机网络简笔画,电脑卡通简笔画图片
  11. hl7消息介绍_消息格式及编码规则-HL7协议学习笔记(转)
  12. PHP的性能演进(从PHP5.0到PHP7.1的性能全评测)
  13. 深入理解LCD之寄存器配置
  14. 使用web设计器制作图表报表
  15. 码云Gitee WebHook Jenkins 403 err:No valid crumb was included in the request
  16. 此计算机未连接到网络.单击以连接,此计算机无法连接到家庭组win7
  17. 假设检验(显著性检验)
  18. 【Java】poi | excel | 合并单元格
  19. 纯翻译 GMSL2-CSI2 MAX9295和MAX9296配对通用过程 编程指南
  20. 音视频技术开发周刊 79期

热门文章

  1. Windows中的用户和组以及用户密码处理
  2. CAD 2022卸载方法,如何完全彻底卸载删除清理干净CAD各种残留注册表和文件? 【转载】
  3. 数仓架构--之数据拉链表实操
  4. 谷歌硬盘 idm_为什么Google搜索结果比本地硬盘查询要快?
  5. c语言程序设计新教材,《C语言程序设计》教学大纲(新)教材.doc
  6. Kaggle:Tabular Playground Series - May 2021
  7. 中科大EPC自动程序(2022python版)
  8. 微信计步器怎么不计步_微信运动不计步,如何解决
  9. Android 四大组件
  10. 网页版excel数据批量导入数据库