Linux IPC 之信号量
信号量(也叫信号灯)是一种用于提供不同进程间或一个给定进程的不同线程间同步手段的原语。
信号量是进程/线程同步的一种方式,有时候我们需要保护一段代码,使它每次只能被一个执行进程/线程运行,这种工作就需要一个二进制开关;
有时候需要限制一段代码可以被多少个进程/线程执行,这就需要用到关于计数信号量。信号量开关是二进制信号量的一种逻辑扩展,两者实际调用的函数都是一样。
信号量分为以下三种。
1、System V信号量,在内核中维护,可用于进程或线程间的同步,常用于进程的同步。
2、Posix有名信号量,一种来源于POSIX技术规范的实时扩展方案(POSIX Realtime Extension),可用于进程或线程间的同步,常用于线程。
3、Posix基于内存的信号量,存放在共享内存区中,可用于进程或线程间的同步。
为了获得共享资源进程需要执行下列操作:
(1)测试控制该资源的信号量。
(2)若信号量的值为正,则进程可以使用该资源。进程信号量值减1,表示它使用了一个资源单位。此进程使用完共享资源后对应的信号量会加1。以便其他进程使用。
(3)若信号量的值为0,则进程进入休息状态,直至信号量值大于0。进程被唤醒,返回第(1)步。
为了正确地实现信号量,信号量值的测试值的测试及减1操作应当是原子操作(原子操作是不可分割的,在执行完毕不会被任何其它任务或事件中断)。为此信号量通常是在内核中实现的。
·System V IPC机制:信号量。
函数原型:
#include <sys/sem.h>
#include <sys/ipc.h>
#include <sys/types.h>
int semget(key_t key,int nsems,int flag);
函数semget创建一个信号量集或访问一个已存在的信号量集。返回值:成功时,返回一个称为信号量标识符的整数,semop和semctl会使用它;出错时,返回-1.
参数key是唯一标识一个信号量的关键字,如果为IPC_PRIVATE(值为0,创建一个只有创建者进程才可以访问的信号量,通常用于父子进程之间;非0值的key(可以通过ftok函数获得)表示创建一个可以被多个进程共享的信号量;
参数nsems指定需要使用的信号量数目。如果是创建新集合,则必须制定nsems。如果引用一个现存的集合,则将nsems指定为0.
参数flag是一组标志,其作用与open函数的各种标志很相似。它低端的九个位是该信号量的权限,其作用相当于文件的访问权限。此外,它们还可以与键值IPC_CREAT按位或操作,以创建一个新的信号量。即使在设置了IPC_CREAT标志后给出的是一个现有的信号量的键字,也并不是一个错误。我们也可以通过IPC_CREAT和IPC_EXCL标志的联合使用确保自己将创建出一个新的独一无二的信号量来,如果该信号量已经存在,就会返回一个错误。
int semop(int semid,struct sembuf *sops,size_t nops);
函数semop用于改变信号量对象中各个信号量的状态。返回值:成功时,返回0;失败时,返回-1.
参数semid是由semget返回的信号量标识符。
参数sops是指向一个结构体数组的指针。每个数组元素至少包含以下几个成员:
struct sembuf{
short sem_num; //操作信号在信号集中的编号,第一个信号的编号是0。 /*通常只会用到两个值,一个是-1,也就是p操作,它等待信号量变为可用;
一个是+1,也就是v操作,它发送信号通知信号量现在可用。
sem_op成员的值是信号量在一次操作中需要改变的数值*/
short sem_op; short sem_flg; //通常设为:SEM_UNDO,程序结束,信号量为semop调用前的值。
};
参数nops为sops指向的sembuf结构数组的大小。
int semctl(int semid, int semnum, int cmd, …);
函数semctl用来直接控制信号量信息。函数返回值:成功时,返回0;失败时,返回-1.
参数semid是由semget返回的信号量标识符。
参数semnum为集合中信号量的编号,当要用到成组的信号量时,从0开始。一般取值为0,表示这是第一个也是唯一的一个信号量。
参数cmd为执行的操作。通常为:IPC_RMID(立即删除信号集,唤醒所有被阻塞的进程)、GETVAL(根据semnun返回信号的值)、SETVAL(根据semun设定信号的值)、GETALL(获取所有信号量的值,第二个参数为0,将所有信号的值存入semun.array中)、SETALL(将所有semun.array的值设定到信号集中,第二个参数为0)等。
参数…是一个union semun(需要由程序员自己定义),它至少包含以下几个成员:
union semun{
int val; /* Value for SETVAL */ struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */ unsigned short *array; /* Array for GETALL, SETALL */
};
示例:
sem1.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h> //P操作,申请一个资源
void P(int semid)
{
struct sembuf my_buf;
memset(&my_buf,,sizeof(my_buf));
my_buf.sem_num = ;
my_buf.sem_op = -;
my_buf.sem_flg = SEM_UNDO;
semop(semid,&my_buf,);
} void V(int semid)
{
struct sembuf my_buf;
memset(&my_buf,,sizeof(my_buf));
my_buf.sem_num = ;
my_buf.sem_op = ;
my_buf.sem_flg = SEM_UNDO;
semop(semid,&my_buf,);
} int main(int *argc, char *argv[])
{
key_t my_key = ;
int my_sem; //创建一个信号量集或访问一个已存在的信号量集
my_sem = semget(my_key,, | IPC_CREAT);
if(my_sem == -)
{
printf("semget error!\n");
exit();
}
printf("before setval: %d\n",semctl(my_sem,,GETVAL));
printf("setting val...\n"); semctl(my_sem,,SETVAL,);
printf("After setval:%d\n",semctl(my_sem,,GETVAL));
P(my_sem);
while(getchar() != EOF);
V(my_sem); sleep();
semctl(my_sem,,IPC_RMID); return ;
}
sem2.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h> void P(int semid)
{
struct sembuf my_buf;
memset(&my_buf,,sizeof(my_buf));
my_buf.sem_num = ;
my_buf.sem_op = -;
my_buf.sem_flg = SEM_UNDO;
semop(semid,&my_buf,);
} void V(int semid)
{
struct sembuf my_buf;
memset(&my_buf,,sizeof(my_buf));
my_buf.sem_num = ;
my_buf.sem_op = ;
my_buf.sem_flg = SEM_UNDO;
semop(semid,&my_buf,);
} int main(int *argc, char *argv[])
{
key_t my_key = ;
int my_sem; my_sem = semget(my_key,,);
if(my_sem == -)
{
printf("semget error!\n");
exit();
}
printf("getval:%d\n",semctl(my_sem,,GETVAL)); printf("p....\n");
P(my_sem);
printf("sem1 finished!\n");
V(my_sem); return ;
}
Linux IPC 之信号量的更多相关文章
- Linux IPC POSIX 信号量
模型 #include<semaphore.h> #include<sys/stat.h> #include<fcntl.h> sem_open() //初始化并打 ...
- linux IPC的信号量
信号量相关函数原型 获得一个信号量ID #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h&g ...
- 【转载】Linux的进程间通信-信号量
原文:Linux的进程间通信-信号量 Linux的进程间通信-信号量 版权声明: 本文章内容在非商业使用前提下可无需授权任意转载.发布. 转载.发布请务必注明作者和其微博.微信公众号地址,以便读者询问 ...
- System V IPC 之信号量
本文继<System V IPC 之共享内存>之后接着介绍 System V IPC 的信号量编程.在开始正式的内容前让我们先概要的了解一下 Linux 中信号量的分类. 信号量的分类 在 ...
- Linux IPC实践(1) -- 概述
进程的同步与互斥 进程同步: 多个进程需要相互配合共同完成一项任务. 进程互斥: 由于各进程要求共享资源,而且有些资源需要互斥使用,因此各进程间竞争使用这些资源,进程的这种关系为进程的互斥;系统中某些 ...
- linux ipc/its
linux进程间双向消息队列 server.c #include <stdio.h> #include <stdlib.h> #include <string.h> ...
- Linux多线程编程-信号量
在Linux中.信号量API有两组.一组是多进程编程中的System V IPC信号量.另外一组是我们要讨论的POSIX信号量. 这两组接口类似,但不保证互换.POSIX信号量函数都已sem_开头,并 ...
- Linux IPC之共享内存C 事例
Linux IPC之共享内存 标签: linuxrandomnull工作 2011-08-25 11:52 4123人阅读 评论(0) 收藏 举报 分类: Linux(3) 读书札记(3) 版权 ...
- linux 下的信号量参数
linux 下的信号量参数 转载自:http://blog.itpub.net/26110315/viewspace-718306/ 信号量是一种锁机制用于协调进程之间互斥的访问临界资源.以确保某种共 ...
随机推荐
- Error 2503 and 2502 when installing/uninstalling on Windows 10
1. Hold Ctrl+Shift and press Esc. 2. Locate “Windows Explorer” under “Windows processes”, now right ...
- CVE2016-8863libupnp缓冲区溢出漏洞原理分析及Poc
1.libupnp问题分析: (1)问题简述: 根据客户给出的报告,通过设备安装的libupnp软件版本来判断,存在缓冲区溢出漏洞:CVE-2016-8863. (2)漏洞原理分析: 该漏洞发生在up ...
- jsp常见的指令总结
一.三个编译指令 1.page指令: 首先,我们要明确一点就是page指令是一个全局指令,针对当前页面,其次我们再来深挖他的功能,它到底有哪些功能那,在我们程序中起到什么作用??? a.语法结构:&l ...
- ArcGIS案例学习笔记3_1
ArcGIS案例学习笔记3_1 联系方式:谢老师,135_4855_4328,xiexiaokui#139.com 时间:第三天上午 内容1:ArcGIS 平台介绍 体系结构 Arcgis for d ...
- 【Linux】svn环境配置
Ubuntu 安装svn环境配置 1. 安装 sudo apt-get install subversion 安装过程需要数据[Y] 2. svn位置选择 安装完成之后,选择svn目录位置, 将其放在 ...
- Mycat入门及简单规则
以下都来自网络: 官网: http://www.mycat.io/ 官网配置文件解析: https://github.com/MyCATApache/Mycat-Server/wiki/9.0-%E6 ...
- Hadoop 初始化系统
hadoop namenode -format 或者 hdfs namenode -format 2.执行hadoop sbin 目录下的 start-dfs.sh start-yarn.sh3.查看 ...
- HTML的标签简介
1.标签的简介: <html>与</html>之间的文本描述网页<head>与</head>之间的标签用于定义文档的头部,他是所有的头部的文件<b ...
- springboot+cxf 开发webservice
参考 https://www.cnblogs.com/fuxin41/p/6289162.html pom.xml <?xml version="1.0" encoding= ...
- svn: authentication cancelled
从svn 下程序时用户名和密码输入正确后报如图错误! 控制台输出: svn: authentication cancelled svn: authentication cancelled ...