进程间通讯——信号量

来源:互联网 发布:大众网络投资产品排行 编辑:程序博客网 时间:2024/06/05 00:21

信号量:通过管理对资源的访问,实现进程间同步控制。

在了解信号量的机制之前我们先了解几个与信号量有关的知识点:

(1) 临界资源:同一时刻只能呗同一个进程访问的资源;

(2) 原子操作:任何情况下都不能被打断的操作 ;

(3) 内核对象:用于进程通讯时,多进程能够访问同一资源的记录;


1、信号量的定义:

     它是一个特殊变量,它只取正整数值,并且程序对信号量的访问都是原子操作,只允许对它进行等待和发送信号两种操作,下面 

     会解释这两种操作。

2、信号量的操作:

 (1) 创建或获取:如果是创建必须初始化;如果是获取则不能初始化;

 (2) 减一操作(P操作):假设一个信号量变量sv(下同),如果sv的值大于零,就给它减去一;如果sv的值等于零,就挂起该进程的执

      行;

 (3) 加一操作(v操作):如果有其他进程因等待sv而被挂起,就让它恢复运行;如果没有进程因等待sv而被挂起,就给它加一;

 (4) 删除操作:因为有内核对象。

3、信号量有关的函数:

 (1) semget函数:创建一个新信号量或获取一个已有信号量的键。

      int semget(key_t key,int sems,int flag);

      key:键值,一个非零整数,类似于信号量组中信号量的一个“身份证号”,不相关的进程可以通过它访问同一个信号量;

      sems:指定需要的信号量数目,它的取值几乎总是1;

      flag:其作用类似于文件的访问权限,可以和IPC_CREAT做按位或操作,信号量不存在时创建,存在时即获取;

      返回值:semget函数成功时返回一个正数值,即信号量标识符;失败则返回-1.

 (2) semop函数:用于改变信号量的值,即完成p操作或v操作。

      int semop(int semid,struct sembuf *buf,size_t num_sem_ops);

      semid:由semget返回的信号量标识符;

      buf:指向一个结构数组的指针,每个数组元素包括以下几个成员:

           struct sembuf{

                   short sem_num;  //信号量编号,除非使用一组信号量,否则一般为0;

                   short sem_op;    //信号量再一次操作中需要改变的数值,p操作:-1,v操作:+1;

                   short sem_flag;  //通常为SEM_UNDO,是操作系统跟踪当前进程对这个信号量的修改情况

              };

 (3) semctl函数:用来直接控制信号量信息。

      int semctl(int sem_id,int sem_num,int command,/*union semun un*/);

      sem_id:由semget返回的信号量标识符;

      sem_num:信号量编号,当需要用到组信号量时就需要用到这个参数,一般取值为0,表示这是第一个也是唯一的一个信号

                         量。

      command:将要采取的动作,SETVAL初始化信号量,IPC_RMID删除一个无需继续使用的信号量标识符;

      un:是一个union_semun的结构体,次结构体必须由程序员自己定义,包含以下几个成员:

              union semun{

                       int val;

                       struct semid_ds *buf;

                       unsigned short *array;

                   }

4、信号量函数的封装:

      // 头文件

 #ifndef SEM_H

#define SEM_H

#include<stdio.h>

#include<stdlib.h>

#include<unistd.h>

#include<string.h>

#include<assert.h>

#include<sys/types.h>

#include<sys/ipc.h>

#include<sys/sem.h>

int semid;

union semun
{
 int val;
};

void sem_get(int key,int len,int val);
void sem_p();
void sem_v();
void sem_del();

#endif


//.c文件

#include"sem.h"

void sem_get(int key,int len,int val)
{
 semid = semget((key_t)key,len,0666);
 if(semid == -1)
 {
  semid = semget((key_t)key,len,0666|IPC_CREAT);
  assert(semid != -1);

  union semun v;
  v.val = val;
  if(semctl(semid,0,SETVAL,v) == -1)
  {
   perror("error");
   exit(0);
  }
 }
}

void sem_p()
{
 struct sembuf sem;
 sem.sem_num = 0;
 sem.sem_op = -1;
 sem.sem_flg = SEM_UNDO;

 if(semop(semid,&sem,1) == -1)
 {
  perror("error");
  exit(0);
 }
}

void sem_v()
{
 struct sembuf sem;
 sem.sem_num = 0;
 sem.sem_op = 1;
 sem.sem_flg = SEM_UNDO;

 if(semop(semid,&sem,1) == -1)
 {
  perror("error");
  exit(0);
 }
}

void sem_del()
{
 if(semctl(semid,0,IPC_RMID) == -1)
 {
  perror("error");
  exit(0);
 }
}


       

                       






原创粉丝点击