您的位置:首页 > 其它

System V 信号量机制

2016-07-10 23:53 417 查看
有三种 IPC我们称作XSI IPC,即消息队列、信号量以及共享存储器(共享内存),这就是我么所说的进程间通信的IPC,有了这些IPC提供给程序的通信接口,实现进程间的通信

本文主要讨论的是信号量的机制

semget()创建一个新的信号量集,或者存取一个已经存在的信号量集:

系统调用:semget();

原型:int semget(key_t key,int nsems,int semflg);

返回值:如果成功,则返回信号量集的IPC标识符。如果失败,则返回-1:errno=EACCESS(没有权限)

EEXIST(信号量集已经存在,无法创建)

EIDRM(信号量集已经删除)

ENOENT(信号量集不存在,同时没有使用IPC_CREAT)

ENOMEM(没有足够的内存创建新的信号量集)

ENOSPC(超出限制)

系统调用semget()的第一个参数是关键字值(一般是由系统调用ftok()返回的)。系统内核将此值和系统中存在的其他的信号量集的关键字值进行比 较。打开和存取操作与参数semflg中的内容相关。IPC_CREAT如果信号量集在系统内核中不存在,则创建信号量集。IPC_EXCL当和 IPC_CREAT一同使用时,如果信号量集已经存在,则调用失败。如果单独使用IPC_CREAT,则semget()要么返回新创建的信号量集的标识 符,要么返回系统中已经存在的同样的关键字值的信号量的标识符。如果IPC_EXCL和IPC_CREAT一同使用,则要么返回新创建的信号量集的标识
符,要么返回-1。IPC_EXCL单独使用没有意义。参数nsems指出了一个新的信号量集中应该创建的信号量的个数。

程序举例:

<span style="font-family:Microsoft YaHei;font-size:14px;">intopen_semaphore_set(key_t keyval,int numsems)
{
intsid;
if(!numsems)
return(-1);
if((sid=semget(mykey,numsems,IPC_CREAT|0660))==-1)
{
return(-1);
}
return(sid);
};</span>


semop函数使用semget打开一个信号量集后,对其中一个或多个信号量的操作就使用semop(op--operate)函数来执行。
原型:int semop(int semid, struct sembuf *opsptr, size_t nops);

参数:semid:是semget返回的semid号。

nops:是数组opsptr的个数。

opsptr是操作结构的数组

struct sembuf

{

short sem_num; //信号量在semid集合中的序号:0到nsems - 1;

short sem_op; //操作

short sem_flag; //0, IPC_NOWAIT, SEM_UNDO

};

其中,sem_op值如下:

a、如果sem_op大于0,表示sem_num信号量所代表的资源的释放,semval += sem_op;

b、如果sem_op小于0,表示sem_num信号量所代表资源的分配,具体是:如果semval 大于等于 sem_op的绝对值,则semval -= sem_op绝对值;否则,阻塞知道条件满足

c、如果sem_op等于0,表示直到semval 等于0时才返回。

程序举例:

<span style="font-family:Microsoft YaHei;font-size:14px;">static int op_sem(int sem_id, int op, int which)//信号量的操作举例
{
struct sembuf sem;
memset(&sem, '\0', sizeof(sem));
sem.sem_num = which;
sem.sem_op = okp;
sem.sem_flg = 0;
return semop(sem_id, &sem, 1);
}</span><pre name="code" class="cpp"><span style="font-family:Microsoft YaHei;">int sem_p(int sem_id, int which)//P操作
{
int ret = op_sem(sem_id, -1, which);
if(ret == 0){
printf("P operator is success!, errno code is : %d\n", errno);
}else{
printf("P operator is failed!, errno code is : %d\n", errno);
}
return ret;
}
int sem_v(int sem_id, int which)//V操作
{
int ret = op_sem(sem_id, 1, which);
if(ret == 0){
printf("V operator is success!, errno code is : %d\n", errno);
}else{
printf("V operator is failed!, errno code is : %d\n", errno);
}
return ret;
}</span>




semctl函数用来直接控制信号量信息。

原型:int semctl(int semid, int semnum, int cmd, ../* union semun arg */);

其中semid是信号量集合,semnum是信号在集合中的序号,

union semun

{

int val; /* cmd == SETVAL */

struct semid_ds *buf /* cmd == IPC_SET或者 cmd == IPC_STAT */

ushort *array; /* cmd == SETALL, 或 cmd = GETALL */

};

cmd取值如下:

GETVAL, SETVAL : semid集合中semnum信号量当前的semval值

GETALL,SETALL :semid集合中所有信号量的值。

IPC_RMID:删除semid信号量集

GETPID:返回最后成功操作该信号的进程号。

IPC_STAT:返回semid集合中的struct semid_ds结构。

程序举例:

<span style="font-family:Microsoft YaHei;font-size:14px;">int destroy_sem(int sem_id)//使用semctl删除信号量
{
int ret = semctl(sem_id, 0, IPC_RMID, NULL);
if(ret == -1){
printf("destroy sem error\n");
return ret;
}
printf("destroy sem success, errno code is : %d\n", errno);
return ret;
}</span>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: