信号量 semget函数、semop函数、semctl函数

semget函数
创建信号量集

int semget( key_t key, int nsems, int flag);
//such as:
			semId = semget(key,1,IPC_CREAT|0666);
			if(semId == -1){
				perror("semget");
				return -1;
			}

参数 nsems

是信号量集里面的信号量的个数

参数 flag

是信号量的操作类型以及操纵权限

semop函数
函数semop用以操作一个信号量集

通常用在PV操作中

int semop( int semid, struct sembuf semoparray[], size_t nops );
/*  struct sembuf sops[2];
                int semid;

                sops[0].sem_num = 0;              
                sops[0].sem_op = 0;               
                sops[0].sem_flg = 0;

                sops[1].sem_num = 0;             
                sops[1].sem_op = 1;               
                sops[1].sem_flg = 0;*/
                
//such as:  
// 二进制信号量(binary semaphore):只允许信号量取0或1值   
// 信号量集只有一个信号量      
void pKey(int semid)
{
        struct sembuf sops;

        sops.sem_num = 0; 
        sops.sem_op  = -1;      
        sops.sem_flg = SEM_UNDO;

        semop(semid,&sops,1);
}
void vKey(int semid)
{
        struct sembuf sops;

        sops.sem_num = 0;
        sops.sem_op  = 1;       
        sops.sem_flg = SEM_UNDO;

        semop(semid,&sops,1);
}

第一个参数 semid

semget函数的返回值

第二个参数 semoparray[]

是一个struct sembuf结构类型的数组指针

struct sembuf{
		unsigned short sem_num;
		short sem_op;
		short sem_flg;
}

sem_num是相对应的信号量集中的某一个资源,所以其值是一个从0到相应的信号量集的资源总数(ipc_perm.sem_nsems)之间的整数。

sem_op指明所要执行的操作,sem_op的值是一个整数。

sem_flg说明函数semop的行为。

第三个参数 nops

参数nops标明了参数semoparray所指向数组中的元素个数

注意:sem_op 详细解释,其实,看也看不懂

sem_op  正数
释放相应的资源数,将sem_op的值加到信号量的值上
sem_op  0
进程阻塞直到信号量的相应值为0,当信号量已经为0,函数立即返回。如果信号量的值不为0,则依据sem_flg的IPC_NOWAIT位决定函数动作。sem_flg指定IPC_NOWAIT,则semop函数出错返回EAGAIN。sem_flg没有指定IPC_NOWAIT,则将该信号量的semncnt值加1,然后进程挂起直到下述情况发生。信号量值为0,将信号量的semzcnt的值减1,函数semop成功返回;此信号量被删除(只有超级用户或创建用户进程拥有此权限),函数smeop出错返回EIDRM;进程捕捉到信号,并从信号处理函数返回,在此情况将此信号量的semncnt值减1,函数semop出错返回EINTR
sem_op  负数
请求sem_op的绝对值的资源。如果相应的资源数可以满足请求,则将该信号量的值减去sem_op的绝对值,函数成功返回。当相应的资源数不能满足请求时,这个操作与sem_flg有关。sem_flg指定IPC_NOWAIT,则semop函数出错返回EAGAIN。sem_flg没有指定IPC_NOWAIT,则将该信号量的semncnt值加1,然后进程挂起直到下述情况发生:当相应的资源数可以满足请求,该信号的值减去sem_op的绝对值。成功返回;此信号量被删除(只有超级用户或创建用户进程拥有此权限),函数smeop出错返回EIDRM:进程捕捉到信号,并从信号处理函数返回,在此情况将此信号量的semncnt值减1,函数semop出错返回EINTR

semctl函数 执行在信号量集上的控制操作

int semctl(int semid,int semnum,int cmd, /*union semun arg*/);
union semun {
        int                      val;    /* Value for SETVAL */
        struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
        unsigned short  *array;  /* Array for GETALL, SETALL */
        struct seminfo  *__buf;  /* Buffer for IPC_INFO
                                                                (Linux-specific) */
};
//需要注意的是,对于semun联合体,最好自己定义,否则GCC编译器可能会报“semun大小未知”
//such as:
semctl(semId,0,SETVAL,initsem);

第一个参数是信号量集IPC标识符。
第二个参数是操作信号在信号集中的编号,第一个信号的编号是0。

第三个参数cmd

·IPC_STAT读取一个信号量集的数据结构semid_ds,并将其存储在semun中的buf参数中。
·IPC_SET设置信号量集的数据结构semid_ds中的元素ipc_perm,其值取自semun中的buf参数。
·IPC_RMID将信号量集从内存中删除。
·GETALL用于读取信号量集中的所有信号量的值。
·GETNCNT返回正在等待资源的进程数目。
·GETPID返回最后一个执行semop操作的进程的PID。
·GETVAL返回信号量集中的一个单个的信号量的值。
·GETZCNT返回正在等待完全空闲的资源的进程数目。
·SETALL设置信号量集中的所有的信号量的值。
·SETVAL设置信号量集中的一个单独的信号量的值。

下面有个简单的例子来使用这些API

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdlib.h>
#include <unistd.h>

union semun {
	int 			 val;	 /* Value for SETVAL */
	struct semid_ds *buf;	 /* Buffer for IPC_STAT, IPC_SET */
	unsigned short	*array;  /* Array for GETALL, SETALL */
	struct seminfo	*__buf;  /* Buffer for IPC_INFO
								(Linux-specific) */
};

void pKey(int semid)
{
	struct sembuf sops;
	
	sops.sem_num = 0;		  
	sops.sem_op  = -1; 	  
	sops.sem_flg = SEM_UNDO;
	semop(semid,&sops,1);
}
void vKey(int semid)
{
	struct sembuf sops;
	
	sops.sem_num = 0;		  
	sops.sem_op  = 1; 	  
	sops.sem_flg = SEM_UNDO;
	semop(semid,&sops,1);
}

int main(int argc,char**argv)
{	
	key_t key;
	int pid;
	int semId;

	key = ftok(".",1);
	semId = semget(key,1,IPC_CREAT|0666);
	union semun initsem;
	initsem.val = 0;
	semctl(semId,0,SETVAL,initsem);

	pid = fork();
	if(pid>0){
		sleep(3);
		printf("this is in father\n");
		vKey(semId);
	}else if(pid == 0){
		pKey(semId);
		printf("this is in chird\n");
		vKey(semId);
		semctl(semId,0,IPC_RMID);
	}else{
		perror("fork error:");
		return -1;
	}
	
	return 0;
}
  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值