Linux进程IPC浅析[进程间通信SystemV进程的信号量和信号量集]

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");
  }
}

以下就是关于信号量的相关的封装操作
欢迎持续访问博客

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值