IPC进程间通信---信号量
信号量
信号量:信号量是一个计数器,常用于处理进程或线程的同步问题,特别是对于临界资源访问的同步。临界资源可以
理解为在某一时刻只能由一个进程或线程操作的资源,这里的资源可以是一段代码、一个变量或某种硬件资源。信号量的
值大于或等于0时表示可供并发进程使用的资源实体数,小于0时表示正在等待使用临界资源的进程数。
Linux内核也为每个信号集维护了一个semid_ds数据结构实例,该结构定义在头文件linux/sem.h中,各个字段含义为:
struct semid_ds
{
struct ipc_perm sem_perm; //对信号进行操作的许可权
__kernel_time_t sem_otime; //对信号进行操作的最后时间
__kernel_time_t em_ctime; //对信号进行修改的最后时间
struct sem *sembase; //指向第一个信号
struct sem_queue sem_pending; //等待处理的挂起操作
struct sem_queue **sem_pending_last; //最后一个正在挂起的操作
struct sem_undo *undo; //撤销的请求
ushort sem_nsems; //数组中的信号数
};
信号量使用key_t值作为它的名字。头文件<sys/types.h>把key_t这个数据类型定义为一个整数,它通常是一个至少32位
的整数。这些整数值通常由ftok函数赋予的。函数ftok把一个已存在的路径名和一个整数标识符转换成一个key_t值,称为
IPC键。该函数原形为:
#include <sys/ipc.h>
key_t ftok(const char *pathname,int proj_id);
创建或打开信号量前需要使用ftok函数得到key值,下面是ftok函数的包裹函数:
key_t Ftok(const char *pathname,int proj_id)
{
key_t key= ftok(pathname,proj_id);
if(key== -)
{
perror("ftok.");
exit();
}
return key;
}
信号量的创建或打开:
Linux下使用系统函数semget函数创建或打开信号量。该函数定义在头文件<sys/sem.h>中,该函数的原形为:
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key,int nsems,int semflg);
该函数执行成功返回一个信号量的标示符,失败返回-1。函数的第一个参数为ftok()函数得到的键值,第二个参数nsems
指明要创建的信号量包含的信号量个数,如果只是打开信号量,把nsems设置为0即可,第三个参数semflg为操作标志,可
以取如下值:
- IPC_CREAT:调用semget()时,它会将此值与系统中其它信号量的key值进行比较,如果存在相同的key,说明此信号量
已存在,此时返回该信号量的标识符,否则新建一个信号量并返回其标识符。
- IPC_EXCL:该宏必须和IPC_CREAT一起使用,否则没有意义。当semflg取IPC_CREAT|IPC_EXCL时,表示如果发现信号
量已经存在,则返回错误,错误码为EEXIST。
信号量的控制:
使用信号量时,往往需要对信号量进行一些控制操作,比如删除信号量、对内核维护的信号量的数据结构semid_ds进行
设置、获取信号量中信号值等。通过semctl控制函数可以完成这些操作,该函数定义在<sys/sem.h>中,如下所示:
int semctl(int semid,int semnum,int cmd, ...);
函数中,参数semid为信号量的标示符(即通过semget函数的到的值);参数semnum标示一个特定的信号;参数cmd指明控制
操作的类型;最后的“...”说明函数的参数是可选的,它依赖于第三个参数cmd,它通过共用体变量semun选择要操作的参数。
union semun
{
int val; //仅用于SETVAL操作类型,设置某个信号量的值等于val
struct semid_ds *buf; //用于IPC_STAT和IPC_SET操作,存取semid_ds结构
unsigned short *array; //用于SETALL和GETALL操作
struct seminfo *__buf; //为控制IPC_INFO提供的缓存
};
参数cmd通过宏来指示操作类型,通常取以下几个宏:
- GETVAL:把semval的当前值作为函数返回值返回。既然信号量决不会时负数(semval被声明为一个unsigned short整数),
那么成功的返回值总是非负数。
- SETVAL:把semval值设置为val。如果操作成功,那么相应信号量在所有进程中的信号量调整值将被设置为0。
- IPC_RMID:把由semid指定的信号量集从系统中删除掉。
信号量的操作:
信号量的值与相应资源的使用情况有关,当它的值大于0时,表示当前可用资源的数量,当它的值小于0时,其绝对值表
示等待使用该资源的进程个数。信号量的值仅能由PV操作来改变。使用semget打开一个信号量集后,对其中一个或多个信号
量的操作就使用semop函数来执行。该函数原型为:
int semop(int semid,struct sembuf *sops,unsigned nsops);
函数的参数semid为信号量的标示符,参数sops指向进行操作的结构体数组首地址,参数nsops指出将要进行操作的信号量
的个数。semop函数调用成功返回0,否则返回-1。
semop的第二个参数sops指向的结构体数组中,每个sembuf结构体对应一个特定的信号操作。该结构体为:
struct sembuf
{
unsigned short sem_num; //信号量在信号集中的索引
short sem_op; //操作类型
short sem_flg; //操作标志
};
sem_op的取值和意义:
- sem_op>0:信号量加上sem_op的值,表示进程释放控制的资源。
- sem_op=0:如果没有设置IPC_NOWAIT,则调用进程进入睡眠状态,直到信号量值为0;否则进程不会睡眠,直接返回
EAGAIN。
- sem_op<0:信号量加上sem_op的值。若没有设置IPC_NOWAIT,则调用进程阻塞,直到资源可用;否则进程直接返回
EAGAIN。
下面是对信号量进行操作的一个例子:
// myipc.h
#pragma once #include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/msg.h> union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
}; key_t Ftok(const char *pathname,int proj_id)
{
key_t key= ftok(pathname,proj_id);
if(key== -)
{
perror("ftok.");
exit();
}
return key;
}
#include "myipc.h" int main()
{
key_t sem_key= Ftok("mysem",0xff);
int sem_id= semget(sem_key,,IPC_CREAT);
if(sem_id== -)
{
perror("semget.");
exit();
}
else
{
printf("sem key = 0x%x,sem id = %d\n",sem_key,sem_id);
}
int ret;
union semun init;
init.val= ;
semctl(sem_id,,SETVAL,init);
struct sembuf info;
info.sem_num= ;
info.sem_op= ;
info.sem_flg= ;
semop(sem_id,&info,);
ret= semctl(sem_id,,GETVAL);
printf("sem value = %d\n",ret);
ret= semctl(sem_id,,IPC_RMID);
if(ret== -)
{
printf("Remove sem error.\n");
}
else
printf("Remove sem ok.\n");
return ;
}
IPC进程间通信---信号量的更多相关文章
- 【转载】Linux的进程间通信-信号量
原文:Linux的进程间通信-信号量 Linux的进程间通信-信号量 版权声明: 本文章内容在非商业使用前提下可无需授权任意转载.发布. 转载.发布请务必注明作者和其微博.微信公众号地址,以便读者询问 ...
- Android开发之IPC进程间通信-AIDL介绍及实例解析
一.IPC进程间通信 IPC是进程间通信方法的统称,Linux IPC包括以下方法,Android的进程间通信主要采用是哪些方法呢? 1. 管道(Pipe)及有名管道(named pipe):管道可用 ...
- System V IPC 之信号量
本文继<System V IPC 之共享内存>之后接着介绍 System V IPC 的信号量编程.在开始正式的内容前让我们先概要的了解一下 Linux 中信号量的分类. 信号量的分类 在 ...
- 【IPC进程间通信之四】数据复制消息WM_COPYDATA
IPC进程间通信+数据复制消息WM_COPYDATA IPC(Inter-Process Communication,进程间通信). 数据复制消息WM_C ...
- IPC 进程间通信方式——信号量
信号量 本质上是共享资源的数目,用来控制对共享资源的访问. 用于进程间的互斥和同步 每种共享资源对应一个信号量,为了便于大量共享资源的操作引入了信号量集,可对多对信号量一次性操作.对信号量集中所有的操 ...
- UNIX:高级环境编程 - 第十五章 IPC:进程间通信
IPC(InterProcess Communication)进程间通信.为啥没有进程间通信,这是因为进程间都是同步的关系,不需要通信. 1.管道 1.1管道特点: (1)半双工的(即数据只能在一个方 ...
- Linux - 进程间通信 - 信号量
一.概念 简单来讲,信号量是一个用来描述临界资源的资源个数的计数器. 信号量的本质是一种数据操作锁,它本身不具有数据交换的功能,而是通过控制其他的通信资源(文件.外部设备等)来实现进程间通信, 他本身 ...
- Linux进程间通信—信号量
二.信号量(semophore) 信号量是一种计数器,可以控制进程间多个线程或者多个进程对资源的同步访问,它常实现为一种锁机制.实质上,信号量是一个被保护的变量,并且只能通过初始化和两个标准的原子操作 ...
- IPC 进程间通信
linux下进程间通信的几种主要手段简介: 管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它 ...
随机推荐
- 【学习笔记】JDBC数据库连接技术(Java Database Connectivity)
一.JDBC简介 Java是通过JDBC技术实现对各种数据库的访问的,JDBC是Java数据库连接技术的简称.它可以把数据持久保存,是一种持久化机制. 1.持久化 持久化就是将程序中的数据在瞬时状态和 ...
- git rebase 和 git merge 总结
git merge 和 git rebase 都是用于合并分支,但二者是存在区别的. 在使用时,记住以下两点: 当你从 remote 去 pull 的时候,永远使用 rebase(除了一个例外) 当你 ...
- rest-framework框架——认证、权限、频率组件
一.rest-framework登录验证 1.models.py添加User和Token模型 class User(models.Model): name = models.CharField(max ...
- es6新语法的使用
1.声明变量: let 声明变量 作用域代码块作用域{} 尽在模块 先使用后声明 会报错 { let a= 12; alert(a) } let 不允许重复声明同一个变量 const 声明是一个常量, ...
- SharePoint 2013 - App Domain Configuration
1. 首先,在DNS服务器上创建app domain,建议使用一个新domain,而不是当前domain的 sub domain,参考此文章的 Option A: Create a new domai ...
- keychains
keychain在ios中是保存在sqlite数据库中的.这个数据库文件的位置:真机:/private/var/Keychains/keychain-2.db虚拟机:/Users/USER-HOME/ ...
- C++中char*与wchar_t*之间的转换
http://blog.163.com/tianshi_17th/blog/static/4856418920085209414977/ 关于C++中的char*与wchar_t*这两种类型的相互转换 ...
- WCF 的优势和特点
版权声明:本文为博主原创文章,未经博主允许不得转载. 一.理解面向服务(Service-Oriented-Architecture) 是指为了解决在Internet环境下业务集成的需要,通过连接 ...
- Selenium2学习(六)-- 定位神器CSS
前言 大部分人在使用selenium定位元素时,用的是xpath定位,因为xpath基本能解决定位的需求.css定位往往被忽略掉了,其实css定位也有它的价值,css定位更快,语法更简洁.这一篇css ...
- css随笔
1. 关于使用pre标签,且要自动换行 可以使用: word-wrap: break-word; white-space: pre-wrap; 2. 更改placeholder样式 .input::- ...