专题 13 IPC之信号量


1.概述

信号量是一种计数器,用来控制对多个进程共享的资源所进行的访问。它们常被用做一个锁机制。


2.相关数据结构与函数

信号量数据结构:

structsemun

{

intval;//当执行SETVAL命令时,用于指定要把信号量设置成什么值。

structsemid_ds *buf;//当执行命令IPC_STAT/IPC_SET,代表内核中所使用的内部信号量数据结构的一个复制。

unsignedshrot *array;//用在GETALL/SETALL命令中的一个指针。

structseminfo *__buf; //信号量内部结构,内部使用,Linux操作系统特有的。

};


新建信号量函数semget(),原型如下:

intsemget(key_t key, int nsems, int semflg);

semflg是打开信号的方式:

    • IPC_CREAT:如果内核不存在这样的信号量集合,则把它创建出来。

    • IPC_EXCL:与IPC_CREAT一起使用,当信号量存在时,则出错。

信号量操作函数semop(),原型如下:

intsemop(int semid, struct sembuf *sops, unsigned nsops);

其中,sembuf的定义如下:

structsembuf

{

ushortsem_num; //信号量的编号

shortsem_op; //信号量的操作

shortsem_flg; //信号量的操作标志

};

控制信号量参数semctl()

intsemctl(int semid, int semnum, int cmd, …);

cmd的取值如下:

    • IPC_STAT: 获取某个集合的semid_ds结构,并把它存储在semun联合体的buf参数所指定的地址

    • IPC_SET: 设置某个集合的semid_ds结构的ipc_perm成员的值。该命令所取的值是从sumun联合体的buf参数中取到的。

    • IPC_RMID: 从内核中删除该集合。

    • GETALL: 用于获取集合中所有信号量的值。

    • GETNCNT: 返回当前正在等待资源的进程的数目。

    • GETPID: 返回最后一次执行semop调用的进程的PID

    • GETVAL: 返回集合中某个信号量的值。

    • GETZCNT: 返回正在等待资源利用率达到百分之百的进程数目。

    • SETALL: 把集合中所有信号量的值设置为联合体的array成员所包含的对应值。

    • SETVAL: 把集合中的单个信号量的值设置为联合体的val成员的值。

参数arg代表类型semun的一个实例。


3.实例

/*-------------------信号量操作实例------------------------------*/

#include<stdio.h>

#include<sys/types.h>

#include<sys/sem.h>

#include<sys/ipc.h>


typedefint sem_t;


unionsemun

{

intval;

structsemid_ds *buf;

unsignedshort *array;

}arg;


/*创建信号量*/

sem_tCreateSem(key_t key, int value)

{

unionsemun sem;

sem_tsemid;

sem.val= value;


semid= semget(key, 0, IPC_CREAT | 0666);

if(-1 == semid)

{

printf("createsemaphore error\n");

return-1;

}


semctl(semid,0, SETVAL, sem);


returnsemid;

}


/*增加信号量*/

intSem_P(sem_t semid)

{

structsembuf sops = {0, +1, IPC_NOWAIT};

return(semop(semid, &sops, 1));

}


/*减小信号量*/

intSem_V(sem_t semid)

{

structsembuf sops = {0, -1, IPC_NOWAIT};

return(semop(semid, &sops, 1));

}


/*设置信号量的值*/

voidSetvalueSem(sem_t semid, int value)

{

unionsemun sem;

sem.val= value;


semctl(semid,0, SETVAL, sem);

}


/*获取信号量的值*/

intGetvalueSem(sem_t semid)

{

unionsemun sem;

returnsemctl(semid, 0, GETVAL, sem);

}


/*销毁信号量*/

voidDestroySem(sem_t semid)

{

unionsemun sem;

sem.val= 0;

semctl(semid,0, IPC_RMID, sem);

}


intmain(int argc, char *argv[])

{

key_tkey;

intsemid;

chari;

structsemid_ds buf;

intvalue = 0;


key= ftok("/ipc/sem", 'a');


semid= CreateSem(key, 100);

for(i= 0; i <= 3; i++)

{

Sem_P(semid);

Sem_V(semid);

}


value= GetvalueSem(semid);

printf("信号量值为:%d\n",value);


DestroySem(semid);

return0;

}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值