Linux进程IPC浅析[进程间通信SystemV进程的信号量和信号量集]
(对共享资源主要实现互斥同步效果)
1. 进程信号量概念
2. 进程信号量集
进程信号量的概念
本质上就是共享资源的数据(非负的计数器),用来控制对共享资源的访问
用于进程间的互斥和同步
每种共享资源对应一个信号量,为了便于大量共享资源的操作引入了信号量集,可以对所有信号量一次性操作,对信号量集中所有操作可以要求全部成功,也可以要求部分成
二元信号量(信号灯)值为0和1
对信号量进程PV操作
信号量集的相关属性
#include<sys/sem.h>
struct semid_ds{
struct ipc_perm sem_perm; //
unsigned short sem_nsems; //信号量集中信号灯数量
time_t sem_otime; //最后一次对信号量集操作的时间
time_t sem_ctime; //最后改变的时间
}
创建信号量集函数
#include<sys/sem.h>
int semget(key_t key,int nsems,int flag);
返回:成功返回信号量集ID,出错返回-1
参数:
key:用户指定的信号量集键值
nsems:信号量集 中信号量的个数
flag:IPC_CREAT,IPC_EXCL等权限
信号量集的控制函数
#include<sys/sem.h>
int semctl(int semid,int semnum,int cmd,.../*union semun arg*/);
union{
int val;
struct semid_ds *buf;
unsigned short *array;
};
参数:
semid:信号量集ID
semnum:0表示对所有信号量操作,信号量编号从0开始
val:放置获取或设置信号量集中某个信号量的值
buf:信号量集属性指针
array:放置获取或设置信号量集中所有信号量的值
cmd:通过cmd参数设定对信号量集要执行的操作
IPC_STAT 获取信号量集的属性 -->buf
IPC_SET 设置信号量集的属性 -->buf
IPC_RMID 删除信号量集--->buf
GETVAL 返回信号量集的值 -->val
SETVAL 设置semnum信号量的值 -->val
GETALL 获取所有信号量的值 -->array
SETALL 设置所有信号量的初始值 -->array
信号量集的操作函数
#include<sys/sem.h>
int semop(int semid,struct sembuf *sops,size_t nsops);
返回:成功返回0,失败返回-1
用于信号量集中信号量的加减操作
可以用于进程间的互斥和同步
struct sembuf{
unsigned short sem_num;
short sem_op;
short sem_flg; /*IPC_NOWAIT*/
}
参数:
semid:信号量集ID
sops:sembuf结构体数组指针
nsops:第二个参数中结构体数组的长度
sem_num:信号量集中信号量编号
sem_op正数为V操作,负数为P操作,0可以用于对共享资源是否已用完的测试
sem_flag:SEM_UNDO标志,表示在进程结束的时候,相应的操作将被取消,如果设置了那么进程没有释放共享资源就退出时候,内核会取代其释放
一下是对sem的一个简单的封装;
/*
* ===========================================================================
*
* Filename: pv.h
PV操作,P操作表示测试消息是否到达,做-1操作,V操作发送消息,表示+1操作
* Description:
* Version: 1.0
* Created: 2017年04月16日 12时27分03秒
* Revision: none
* Compiler: gcc
* Author: (),
* Company:
*
* ===========================================================================
*/
#ifndef __PV_H
#define __PV_H_
//初始化信号灯/信号量的数值
extern int I(int semnums,int value);
//对信号量集(semid)中的信号灯(semnum)进程P操作
extern void P(int semid,int semnum,int value);
//对信号量集(semid)中的信号灯(semnum)进程V操作
extern void V(int semid,int semnum,int value);
//销毁信号量集
extern void D(int semid);
#endif
/*
* ===========================================================================
*
* Filename: pv.c
* Description:
* Version: 1.0
* Created: 2017年04月16日 13时37分55秒
* Revision: none
* Compiler: gcc
* Author: (),
* Company:
*
* ===========================================================================
*/
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<sys/sem.h>
#include<malloc.h>
union semnu{
int val;
struct semid_ds *buf;
unsigned short *array;
};
/* *
*初始化信号量集
* */
int I(int semnums,int value){
int sem_id = semget(IPC_PRIVATE,semnums,IPC_CREAT | IPC_EXCL | 0777);
if(sem_id < 0){
perror("create sem error");
return -1;
}
union semnu nu;
unsigned short* array = (unsigned short*)calloc(semnums,sizeof(unsigned short));
int i;
for(i = 0 ; i<semnums ;i++){
array[i] = value;
}
nu.array = array;
//初始化信号量集中所有信号灯的初值
if(semctl(sem_id,0,SETALL,nu)<0){
perror("semctl error");
}
free(array);
return sem_id;
}
/* *
*进行P操作(信号减操作)
* */
void P(int semid,int semnum,int value){
assert(value > 0);
//定义一个sembuf类型的结构体数组,防止若干个结构体变量
//对应要操作的信号量,要做的P或者V操作
//因为value是大于0的,所有-value的话,就是做P操作
struct sembuf ops[] = {{semnum,-value,SEM_UNDO}};
if(semop(semid,ops,sizeof(ops)/sizeof(struct sembuf)) < 0){
perror("semop error");
}
}
/* *
*进行V操作(信号加操作)
* */
void V(int semid,int semnum,int value){
assert(value > 0);
//定义一个sembuf类型的结构体数组,防止若干个结构体变量
//对应要操作的信号量,要做的P或者V操作
//因为value是大于0的,所有-value的话,就是做P操作
struct sembuf ops[] = {{semnum,value,SEM_UNDO}};
if(semop(semid,ops,sizeof(ops)/sizeof(struct sembuf)) < 0){
perror("semop error");
}
}
/*
* 删除信号集
*/
void D(int semid){
if(semctl(semid,0,IPC_RMID,NULL) < 0){
perror("semctl error");
}
}
以下就是关于信号量的相关的封装操作
欢迎持续访问博客