IPC——应用二 信号量

23 篇文章 0 订阅

一:首先我们先了解几个概念

1.临界资源:同一时间只能被一个进程或者一个线程访问的资源。
2.临界区:访问临界资源的代码区域。
3.原子操作:

不可被中断的操作,一旦开始执行,只能到其结束。

常见的有P操作,和V操作。

4.进程同步:指为完成某种任务而建立的两个和多个进程,这些进程在合作的过程中需要协调工作次序进行有序的访问而出现等待所产生的制约关系。
5.进程异步:协调无等待。这两者是进程间的运行关系,
6.阻塞运行:正在进行的进程由于发生某事件而暂时无法继续执行时
7.非阻塞运行:  这两者是进程的运行状态。

二:再来了解以下几个问题

1.什么叫做信号量?信号量的实质是什么?

  它与(管道,FIFO,以及消息队列)不同,它是一个计数器,用于多进程对共享对象的访问。--进程同步控制

2.信号量的作用?

  它是用来协调不同进程的数据对象的,而主要的应用是共享内存方式的进程间通信。本质上它是一个计数器,用来记录对某个资源(如共享内存)的存取状况,并且只有两个操作可以改变他们的值(P 和 V 操作)。

三:信号量的系统调用函数

1.系统调用函数semget()

函数头文件 及

函数原型:

#include<sys/sem.h>

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

函数功能:

创建一个新的信号量集,或者获取一个已经存在信号量集。

当调用一个semget创建一个信号量时,他的相应的semid_ds结构已经被初始化。ipc_perm中各个量被设置为相应值:
   sem_nsems被设置为nsems所示的值;
   sem_otime被设置为0;
   sem_ctime被设置为当前时间

 

参数介绍:
1.key:所创建或打开信号量集的键值,键值是IPC_PRIVATE,通常设置为0,;我们也可以通过ftok()函数来取得一个唯一的键值。
2. nsems:

调用函数的操作类型,也可以用于设置信号量集的访问权限,两者通过or来表示:

      有IPC_CREAT,IPC_EXCL两种:

1.IPC_CREAT:如果信号量不存在,则创建一个信号量,否则获取。
2.  IPC_EXCL:只有信号量不存在的时间,新的信号量才建立,否则就产生错误。

 

3. flag:如果成功,返回信号量集的IPC标识符,失败返回-1,

 

返回错误errno
EACCES:没有访问该信号量集的权限
EEXIST:信号量集已经存在,无法创建
EINVAL::参数nsems的值小于0或者大于信号量集的限制;或者是该key关联的信号量集已经存在,并且nsems大于该信号量集的信号量集的信号量数
ENOENT:信号量集不存在,同时没有使用IPC_CREAT
ENOMEM:没有足够的内存创建新的信号量集
ENOSPC:超出系统限制

 

信号量的一些相关值:
semval:信号量的值,一般为一个正整数,他只能通过信号量系统调用semctl函数设置,程序无法直接对它进行修改。
sempid:最后一个堆信号量进行操作的进程的pid
semcnt:等待信号量的值大于当前值的进程数。
semzcnt:等待信号量的值归0的进程数。

2.信号量的控制semctl()

函数头文件 及

函数原型

#include<sys/sem.h>      int semctl ( int semid , int semnum , int cmd , ... /* union semun arg  */);
参数介绍:
  semid为信号量集引用标识符,即semget的返回值。
semnum 信号量的个数。
  cmd

表示调用该函数执行的操作,其取值和对应的操作如下:

IPC_STAT把状态信息放入arg.stat中
IPC_SET用arg.stat中的值设置所有权/许可权
IPC_RMID从系统中删除信号量集合

 

参数arg

代表一个union的semun的实例。semun是在linux/sem.h中定义的:

union semun{

  int val;//执行SETVAL命令时使用

 unsigned short *array;//使用GETALL/SETALL命令时使用的指针

  struct semid_ds *buf;//在IPC_STAT//IPC_SET命令中使用

}

 

功能:semctl函数会依据command参数返回不同的值,他的一个重要的用途就是为信号量赋初值,因为进程违法直接对信号量进行修改。

3.信号量操作semop函数

函数原型:int semop(int semid,struct sembuf semoparray[], size_t nops);
函数功能:在Linux下,PV操作通过调用semop函数来实现,也只有他能对PV进行操作
参数介绍:
semid是信号量集合标识符,它可能是从前的一次semget调用中获得的
senbuf

每个sembuf结构体对应一个特定信号的操作,sembuf结构在,<sys/sem.h>中定义

struct sembuf{

  unsigned short sem_num;/*信号量索引*/

  short sem_op;/*要执行的操作*/

  short sem_flg;/*操作标志*/

}

sem_num存放集合中某一信号量的索引,如果集合中只包含一个元素,则sem_num的值只能为0。

sem_op

取得值为一个有符号整数,该整数实际给定了semop函数将完成的功能。包括三种功情况:

①如果sem_op是负数那么信号量将减去它的值,对应P操作。这和信号量控制的资源有关。如没有使用IPC_NOWAIT,那么调用进程将进入睡眠状态,知道信号量控制的资源可以使用为止。
②如果sem_op是整数则信号量加上它的值,对应V操作。这也是进程释放信号量控制的资源。
③最后如果sem_op为0那么调用进程将调用sleep(),直到信号量的值为0。这在一个进程等待完全空闲的资源时使用。

 

 

函数返回值:

成功返回0,失败返回-1,

errno解析:

E2BIGnsops大于最大的ops数目
EACCESS权限不够
EAGAIN使用了IPC_NOWAIT,但操作不能继续进行
EFAULT sops指向的地址无效
EIDRM信号量集已经删除
EINTR当睡眠时接受到其他信号
EINVAL信号量集不存在,或者semid无效
ENOMEM使用了SEM_UNDO,但无足够的内存创建所需的数据结构
ERANGE信号量超出范围

sem_flg用来告诉系统当前进程退出时自动还原操作,它维护着一个整形变量semadj(信号量的计数器),可设置为IPC_NOWAIT或SEM_UNDO两种状态。只有将sem_flg指定为SEM_UNDO标志后,semadj(所指定信号量针对调用进程的调整值才会更新,即减去sem_num的值。此外如果此操作指定SEM_UNDO,系统更新过程中会撤销此信号量的计数(semadj)。此操作可以随时进行——-他永远不会强制等待的过程。调用进程必须有改变信号量集的权限。

代码展示:

//sem.h文件
#ifndef _SEM_H
#define _SEM_H

#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<fcntl.h>

typedef union semun
{
		int val;
}semun;

int sem_init(int key);

void sem_p(int id,int sem);

void sem_v(int id,int sem);

void sem_del(int id);



#endif
//sem.c文件
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>

#include"sem.h"

int sem_init(int key)
{
		int semid = semget((key_t)key,0,0666);//获取

		if(semid == -1)
		{
				semid = semget((key_t)key,1,0666|IPC_CREAT);//创建

				semun un;
				un.val = 0;//给信号量的初始值,根据需求定制

				semctl(semid,0,SETVAL,un);//初始化
		}
		return semid;
}
void sem_p(int id,int sem)
{
		struct sembuf buf;
		buf.sem_num = sem;
		buf.sem_op = -1;
		buf.sem_flg = SEM_UNDO;

		semop(id,&buf,1);
}
void sem_v(int id,int sem)
{
		struct sembuf buf;
		buf.sem_num = sem;
		buf.sem_op = 1;
		buf.sem_flg = SEM_UNDO;

		semop(id,&buf,1);
}
void sem_del(int id)
{
		semctl(id,0,IPC_RMID);
}

 

 

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值