linux Posix 信号量 一
信号量是一种用于提供不同进程间或一个给定进程的不同线程间同步手段的原语。
linux提供两种信号量,“内核信号量”和“用户态进程信号量”,“用户态信号量”又分为“Posix”,“System V”信号量。
今天我们主要讲解Posix信号量,Posix分为 有名/无名(又称匿名/内存信号量):
1、Posix有名信号量,使用Posix IPC名字标识;
2、Posix匿名信号量,基于内存的信号量,存放在共享内存区中;
无名信号量常用于多线程间的同步,同时也用于相关进程间的同步。也就是说,无名信号量必须是多个进程(线程)的共享变量,无名信号量要保护的变量也必须是多个进程(线程)的共享变量,这两个条件是缺一不可的。
图1 由两个进程使用的一个二值信号量
图2 由两个进程使用的一个Posix有名二值信号量
图3 由一个进程内的两个线程共享的基于内存的信号量
一个进程可以在某个信号量上执行的三种操作:
1、创建一个信号量,这要求调用者指定初始值,对于二值信号量来说,它通常是1,也可是0。
2、等待一个信号量,该操作会测试这个信号量的值,如果小于0,就阻塞。也称为P操作。
3、挂出一个信号量,该操作将信号量的值加1,也称为V操作。
信号量、互斥锁和条件变量之间的三个差异:
1、互斥锁必须总是给它上锁的线程解锁,信号量的挂出却不必由执行过它的等待操作的同一线程执行。
2、互斥锁要么被锁住,要么被解开。
3、既然信号量有一个与之关联的状态,那么信号量挂出操作总是被记住。然而当向一个条件变量发送信号时,如果没有线程等待在该条件变量上,信号丢失。
Posix提供两类信号量:有名信号量和基于内存的信号量(也称无名信号量)。使用函数如下:
- #include <semaphore.h>
- /*sem_open创建一个新的有名信号量或打开一个已存在的有名信号量,value参数指定信号量的初始值,返回值是一个指向某个sem_t数据类型的指针,用作其他函数的参数*/
- sem_t *sem_open(const char *name, int oflag, .../*mode_t mode, unsigned int value*/);
- int sem_close(sem_t *sem); /*一个进程终止时,内核对其上仍打开着的所有信号量自动执行关闭操作*/
- int sem_unlink(const char *name); /*sem_unlink函数:当引用计数大于0时,name就能从文件系统中删除,然而信号量的析构却要等到最后一个sem_close发生时为止*/
- int sem_wait(sem_t *sem); /*测试所指定信号量的值,大于0,将它减1并返回,等于0,调用线程休眠,直到该值大于0,将它减1,函数随后返回*/
- int sem_trywait(sem_t *sem); /*所指定信号量值为0时,不休眠,而是返回一个EAGAIN错误*/
- int sem_post(sem_t *sem);
- int sem_getvalue(sem_t *sem, int *valp);/* 由valp指向的整数中返回所指定信号量的当前值。*/
semcreate程序:
- #include <semaphore.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
- int
- main(int argc, char **argv)
- {
- int c, flags;
- sem_t *sem;
- unsigned int value;
- flags = O_RDWR | O_CREAT;
- value = 1;
- while((c = getopt(argc, argv, "ei:")) != -1){
- switch(c){
- case 'e':
- flags |= O_EXCL;
- case 'i':
- value = atoi(optarg);
- break;
- }
- }
- if(optind != argc - 1){
- printf("usage:semcreate [-e] [-i initalvalue] <name>\n");
- return -1;
- }
- sem = sem_open(argv[optind], flags, FILE_MODE, value);
- sem_close(sem);
- exit(0);
- }
semunlink程序:
- #include <semaphore.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- int
- main(int argc, char **argv)
- {
- if(argc != 2){
- printf("usage:semunlink <name>.\n");
- return -1;
- }
- sem_unlink(argv[1]);
- exit(0);
- }
semgetvalue程序:
- #include <semaphore.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- int
- main(int argc, char **argv)
- {
- sem_t *sem;
- int val;
- if(argc != 2){
- printf("usage:semgetvalue <name>.\n");
- return -1;
- }
- sem = sem_open(argv[1], 0);
- sem_getvalue(sem, &val);
- printf("value = %d\n", val);
- exit(0);
- }
semwait程序:
- #include <semaphore.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- int
- main(int argc, char **argv)
- {
- sem_t *sem;
- int val;
- if(argc != 2){
- printf("usage: semwait <name>");
- return -1;
- }
- sem = sem_open(argv[1], 0);
- sem_wait(sem);
- sem_getvalue(sem, &val);
- printf("pid %ld has semaphore, value = %d\n", (long)getpid(), val);
- pause(); /*block until killed*/
- exit(0);
- }
sempost程序:
- #include <semaphore.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- int
- main(int argc, char **argv)
- {
- sem_t *sem;
- int val;
- if(argc != 2){
- printf("usage:sempost <name>\n");
- return -1;
- }
- sem = sem_open(argv[1], 0);
- sem_post(sem);
- sem_getvalue(sem, &val);
- printf("value = %d\n", val);
- exit(0);
- }
Posix基于内存的信号量,由应用程序分配信号量的内存空间(也就是分配一个sem_t数据类型的内存空间),然后由系统初始化它们的值。
- #include <stmaphore.h>
- int sem_init(sem_t *sem, int shared, unsigned int value); /*出错返回-1*/
- int sem_destroy(sem_t *sem); <span style="white-space:pre"> </span>/*成功返回0,出错返回-1*/
基于内存的信号量是由sem_init初始化的,sem参数指向应用程序必须分配的sem_t变量。如果shared为0,那么待初始化的信号量是在同一进程的各个线程间共享的,否则该信号量是在进程间共享的。
当不需要使用与有名信号量关联的名字时,可改用基于内存的信号量。彼此无亲缘关系的不同进程需要使用信号量时,通常使用有名信号量。其名字就是各个进程标识信号量的手段。基于内存信号量至少具有进程持续性,然而它们真正的持续性却取决于存放信号量的内存区的类型。只要含有某个基于内存信号量的内存区保持有效,该信号量就一直存在。
进程间共享信号量
进程间共享基于内存信号量的规则很简单:信号量本身必须驻留在由所有希望共享它的进程所共享的内存区中,而且sem_init的第二个参数必须是1。
有名信号量,不同进程总是能够访问同一个有名信号量,只要它们在调用sem_open时指定相同的名字即可。
信号量限制
Posix定义了两个信号量限制:
SEM_NSEMS_MAX 一个进程可同时打开着的最大信号数
SEM_VALUE_MAX 一个信号量的最大值
这两个常值定义在<unistd.h>头文件中,可在运行时通过sysconf函数获取。
linux Posix 信号量 一的更多相关文章
- linux POSIX 信号量介绍
信号量一.什么是信号量信号量的使用主要是用来保护共享资源,使得资源在一个时刻只有一个进程(线程)使用.多线程可以同时运行多个线程函数完成功能,但是对于共享数据如果不加以锁定,随意改变共享数据的值会发生 ...
- linux Posix 信号量 二
一.Posix信号量 1.Posix信号量分为两种: 1. 有名信号量:使用Posix IPC名字标识(有名信号量总是既可用于线程间的同步,又可以用于进程间的同步) 2. 内存信号量:存放在共 ...
- linux POSIX信号量
POSIX信号量机制是3种IPC机制之一,3种IPC机制源于POSIX.1的实时扩展. 创建一个新的命名信号量或者使用一个现有信号量 #include <fcntl.h> #include ...
- linux Posix 信号量 三 (经典例子)
本文将阐述一下信号量的作用及经典例子,当中包括“<越狱>寄信”,“家庭吃水果”,“五子棋”,“接力赛跑”,“读者写者”,“四方恋爱”等 首先,讲 semWait操作(P操作)和semSig ...
- Linux进程间通信IPC学习笔记之同步二(Posix 信号量)
Linux进程间通信IPC学习笔记之同步二(Posix 信号量)
- Linux进程同步之POSIX信号量
POSIX信号量是属于POSIX标准系统接口定义的实时扩展部分.在SUS(Single UNIX Specification)单一规范中,定义的XSI IPC中也同样定义了人们通常称为System V ...
- Linux多线程实践(5) --Posix信号量与互斥量解决生产者消费者问题
Posix信号量 Posix 信号量 有名信号量 无名信号量 sem_open sem_init sem_close sem_destroy sem_unlink sem_wait sem_post ...
- linux c编程:Posix信号量
POSIX信号量接口,意在解决XSI信号量接口的几个不足之处: POSIX信号量接口相比于XSI信号量接口,允许更高性能的实现. POSIX信号量接口简单易用:没有信号量集,其中一些接口模仿了我们熟悉 ...
- linux网络编程之posix信号量与互斥锁
继上次学习了posix线程之后,这次来讨论一下posix信号量与互斥锁相关的知识: 跟posix消息队列,共享内存的打开,关闭,删除操作一样,不过,上面的函数是对有名信号量进行操作,通过man帮助可以 ...
随机推荐
- HBase参数优化
zookeeper.session.timeout默认值:3分钟(180000ms)说明:RegionServer与Zookeeper间的连接超时时间.当超时时间到后,ReigonServer会被Zo ...
- windows10下如何进行源码编译安装tensorflow
1.获取python3.5.x https://www.python.org/ftp/python/3.5.4/python-3.5.4-amd64.exe 2.安装python3.5.x,默认安装即 ...
- 获取lambda表达式类型,获取attributes是注意事项
1.获取lambda表达式的MemberExpression所属类的类型,要使用:m.Expression.Type 而不要使用 m.Member.DeclaringType: 后者获取的是实际定 ...
- UVa 11582 巨大的斐波那契数!(幂取模)
https://vjudge.net/problem/UVA-11582 题意: 输入两个非负整数a.b和正整数n,你的任务是计算f(a^b)除以n的余数.f[0]=0,f[1]=1,f[i+2]=f ...
- JS BOM操作
Bom:浏览器对象模型(Browser Object Model,简称 BOM)提供了独立于内容而与浏览器窗口进行交互的对象.描述了与浏览器进行交互的方法和接口,可以对浏览器窗口进行访问和操作 (1) ...
- 使用POI动态更新导出的EXCEL模板中的列
基本思路: 1.从附件服务器上取得模板的流文件 2.拿到流文件之后再使用workbook.write(outs);方法改变流文件中的数据. else if (pageContext.getParame ...
- ssh隧道(通过跳板机)连接mysql
案例: A服务器 B服务器 C服务器mysql 现在mysql服务器C只能通过内网访问,B服务器就能通过内网连接访问到mysql A服务器无法直接连接C服务器mysql,所以要通过跳板机(跳板 ...
- epoll 模型
body, table{font-family: 微软雅黑; font-size: 10pt} table{border-collapse: collapse; border: solid gray; ...
- 单链表是否有环的问题解决与讨论(java实现)
单链表是否有环的问题经常在面试中遇到,一般面试中会要求空间为O(1);再者求若有环,则求环产生时的起始位置. 下面采用java实现. //单链表class ListNode{ int val; Lis ...
- New Concept English Two 6 13
$课文11 礼尚往来 105. I was having dinner at a restaurant when Tony Steele came in. 我正在一家饭馆吃饭,托尼.斯蒂尔走了进来. ...