linux通信之信号量

1.semget()
使用semget()函数来建立新的信号量对象或者获取已有对象的标识符。它在linux/sem.h
中的函数声明是这样的:
系统调用: 
semget()
函数声明: 
int semget ( key_t key, int nsems, int semflg);
返回值: 
semaphore set IPC identifier on success
-1 on error: 
errno = EACCESS (permission denied)
EEXIST (set exists, cannot create (IPC_EXCL))
EIDRM (set is marked for deletion)
ENOENT (set does not exist, no IPC_CREAT was used)
ENOMEM (Not enough memory to create new set)
ENOSPC (Maximum set limit exceeded)
函数参数:
函数接受三个参数。其中第一个参数key 和第三个参数semflg 和前面讲过的msgget()
函数中的两个参数是对应的,作用和取值的意义也相同,读者可以参看msgget()的有关介
绍。函数的第二个参数nsems 是信号量对象所特有的,它指定了新生成的信号量对象中信
号量的数目,也就是信号量数组成员的个数。在linux/sem.h 定义了它的上限:
#define SEMMSL 32 /* <= 512 max num of semaphores per id */有时需要自己定义
2.semop()
使用这个函数来改变信号量对象中各个信号量的状态。它在Linux 系统库linux/sem.h
中的函数声明如下:
系统调用: 
semop()
函数声明: 
int semop ( int semid, struct sembuf *sops, unsigned nsops);
返回值: 0 on success (all operations performed)
-1 on error: 
errno = E2BIG (nsops greater than max number of ops allowed atomically)
EACCESS (permission denied)
EAGAIN (IPC_NOWAIT asserted, operation could not go through)
EFAULT (invalid address pointed to by sops argument)
EIDRM (semaphore set was removed)
EINTR (Signal received while sleeping)
EINVAL (set doesn't exist, or semid is invalid)
ENOMEM (SEM_UNDO asserted, not enough memory to create the undo structure necessary)
ERANGE (semaphore value out of range)
函数参数:
函数的第一个参数semid 是要操作的信号量对象的标识符。第二个参数sops 是sembuf
的数组,它定义了semop()函数所要进行的操作序列。第三个参数nsops 保存着sops 数组
的长度,也即semop()函数将进行的操作个数。
使用例子:
假设我们要向打印机交付一份作业。可以定义下面的sembuf 变量来完成这个操作:
struct sembuf sem_get = { 0, -1, IPC_NOWAIT };
它告诉系统,将信号量对象中序号为零的信号量(第一个信号量)减一。IPC_NOWAIT
标志的定义告诉系统,如果打印机的作业量(10 份)已满,则不阻塞进程而是直接将控制
权返回进程并返回失败信息。定义完操作后,我们使用下面的代码来执行它:
if((semop(sid, &sem_get, 1) == -1)
perror("semop");
作业打印完成后,我们使用下面的sembuf 变量来定义一个释放资源的操作:
struct sembuf sem_release= { 0, 1, IPC_NOWAIT };
它告诉系统将信号量对象中序号为零的对象加一。
然后用下面的代码来完成这个操作:semop(sid,&sem_release,1);
这样,我们就完成了一个完整的作业打印操作。
3.semctl()函数
semctl()函数被用来直接对信号量对象进行控制。它在linux/sem.h 中的函数声明如下:
系统调用: 
semctl()
函数声明: 
int semctl ( int semid, int semnum, int cmd, union semun arg );
返回值: positive integer on success
-1 on error: 
errno = EACCESS (permission denied)
EFAULT (invalid address pointed to by arg argument)
EIDRM (semaphore set was removed)
EINVAL (set doesn't exist, or semid is invalid)
EPERM (EUID has no privileges for cmd in arg)
ERANGE (semaphore value out of range)
主要经常用的cmd如下所示:
IPC_STAT 取得信号量对象的 semid_ds 结构信息,并将其储存在arg 参数中buf 指针所指内存中返回。
IPC_SET 用arg 参数中buf 的数据来设定信号量对象的的semid_ds 结构信息。和消息队列对象一样,能被这个函数设定的只有少数几个参数。
IPC_RMID 从内存中删除信号量对象。
GETALL 取得信号量对象中所有信号量的值,并储存在arg 参数中的array 数组中返回。
GETNCNT 返回正在等待使用某个信号量所控制的资源的进程数目。
GETPID 返回最近一个对某个信号量调用 semop()函数的进程的pid。
GETVAL 返回对象那某个信号量的数值。
GETZCNT 返回正在等待某个信号量所控制资源被全部使用的进程数目。
SETALL 用 arg 参数中array 数组的值来设定对象内各个信号量的值。
SETVAL 用 arg 参数中val 成员的值来设定对象内某个信号量的值。

具体代码如下所示:

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

#define MAX_RESOURCE 5

int main()
{
	key_t key;
	int semid, semval;
	struct sembuf buf_desc = {0, -1, IPC_NOWAIT};//-1 decrease sem
	struct sembuf buf_asc = {0, 1, IPC_NOWAIT};//-1 increase sem
	union semun semopts;

	if((key = ftok(".", 22))== -1) //get the value of key
	{
		perror("ftok error!\n");
		exit(1);
    }

	if((semid = semget(key,1, IPC_CREAT)) == -1)//create sem
	{
		perror("semget error");
		exit(1);
	}
    
	semopts.val = MAX_RESOURCE;
	if(semval =(semctl(semid, 0, SETVAL, semopts)) == -1)//set value of sem
	{
		perror("semctl error");
		exit(1);
    }
	while(1)
	{
		if(semop(semid, &buf_desc, 1) == -1) //decrease the value 
		{
			perror("semop error");
			exit(1);
        }      
        if((semval = semctl(semid, 0, GETVAL, 0)) == -1)//get the value of sem
        {
            perror("semctl error");
            exit(1);
        }
        printf("semval2 = %d\n", semval);//print the value of sem
		sleep(2);
		/*if(semop(semid, &buf_asc, 1) == -1) //increase the sem 
		{
			perror("semop error");
			exit(1);
        }      
        if((semval = semctl(semid, 0, GETVAL, 0)) == -1)//get the value of sem
        {
            perror("semctl error");
            exit(1);
        }
        printf("semval2 = %d\n", semval);//print the value of sem*/
    }
    exit(0);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值