5.2 进程间信号量
进程间信号量的分配,使用和解除分配和共享内存段类似。
5.2.1 分配和解除分配
SYNOPSIS
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);
描述: semget()会返回与参数key 相关的信号量集的标识符.
如果,key 值为 IPC_PRIVATE,
或者,和key相关的信号量集不存在,并且在 semflg中指定了IPC_CREAT,
那么,一个有 nsems个信号量的的新集合将被创建。
如果,semflg指定了 IPC_CREAT和 IPC_EXCL,并且与 key 相关的信号量集已经存在,
那么,semget() 返回 EEXIST.(这与 在 open()中指定了 O_CREAT | O_EXCL 类似。)
semflg的低9位决定了owner,group,others对该信号量集的权限。信号量集的可执行权限是没有意义的。
SYNOPSIS
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semctl(int semid, int semnum, int cmd, ...);
解除信号量的分配,使用 semctl, semid 为要解除的信号量集的标识符,semnum信号量集中信号量的个数,IPC_RMID 指定了消除操作,第四个参数为
任何union semun类型的值(这个值是被忽略的,其内容无关紧要)。
再此处对semctl先不做其他解释。
下面先看一信号量的分配和消除分配的例子,
Listing 5.2 (sem_all_deall.c) Allocating and Deallocating a Binary Semaphore
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
/* We must define union semun ourselves. */
union semun {
int val;
struct semid_ds *buf;
unsigned short int *array;
struct seminfo *__buf;
};
/* Obtain a binary semaphore’s ID, allocating if necessary. */
int binary_semaphore_allocation (key_t key, int sem_flags)
{
return semget (key, 1, sem_flags);
}
/* Deallocate a binary semaphore. All users must have finished their
use. Returns -1 on failure. */
int binary_semaphore_deallocate (int semid)
{
union semun ignored_argument;
return semctl (semid, 1, IPC_RMID, ignored_argument);
}
5.2.2 进程间信号量的初始化
信号量的分配和初始化是两个相互独立的操作。为了初始化一个信号量,还要使用 semctl,第一参数为 线号量集的标识符,0 作为第二个参数,SETALL作为第三个参数。对于第四个参数,你必须创建一个union semun 类型的对象,并且让的array域指向一个 unsigned short 类型的数组。这个数组中的每个值都是用来初始化信号量集中的一个信号量的。
下面是个初始化一个二值信号量的例子,
Listing 5.3 (sem_init.c) Initializing a Binary Semaphore
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
/* We must define union semun ourselves. */
union semun {
int val;
struct semid_ds *buf;
unsigned short int *array;
struct seminfo *__buf;
};
/* Initialize a binary semaphore with a value of 1. */
int binary_semaphore_initialize (int semid)
{
union semun argument;
unsigned short values[1];
values[0] = 1;
argument.array = values;
return semctl (semid, 0, SETALL, argument);
}
5.2.3 wait 和 Post 操作
每个信号量都有一个非负的值,支持wait和post操作。系统调用 semop 可以完成这两种操作。第一个参数为一个信号量集的标识符。第二个参数为一个
struct sembuf 类型的数组,它指定了你想要完成的操作。第三个参数为第二个参数数组的长度。
struct sembuf 的每个域如下,
@ sem_num,是信号量集中的信号量的个数。
@ sem_op,是个整数,制定了信号量的操作。
如果, sem_op 是个正值,那么这个值立即加在信号的值上。
如果, sem_op 是个非正值,那么从信号量的值中减去这个数的绝对值。如果这样做使得信号量的值为负,那么这次调用将阻塞,直到信号量的值
变到大于 sem_op的绝对值。(因为其他进程可能会使信号量的值增加。)
@ sem_flg 是个flag值。如果它指定为 IPC_NOWAIT,那么它将使得 semop操作非阻塞。如果一个进程由于调用了semop应当被阻塞,但是因为指定了
IPC_NOWAIT那么semop将调用失败而返回,却不会阻塞进程。如果指定了SEM_UNDO,Linux自动取消一个退出进程对信号量的操作。
如下为一个二值信号量的 w 和 p 操作示例,
Listing 5.4 (sem_pv.c) Wait and Post Operations for a Binary Semaphore
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
/* Wait on a binary semaphore. Block until the semaphore value is positive, then
decrement it by 1. */
int binary_semaphore_wait (int semid)
{
struct sembuf operations[1];
/* Use the first (and only) semaphore. */
operations[0].sem_num = 0;
/* Decrement by 1. */
operations[0].sem_op = -1;
/* Permit undo’ing. */
operations[0].sem_flg = SEM_UNDO;
return semop (semid, operations, 1);
}
/* Post to a binary semaphore: increment its value by 1.
This returns immediately. */
int binary_semaphore_post (int semid)
{
struct sembuf operations[1];
/* Use the first (and only) semaphore. */
operations[0].sem_num = 0;
/* Increment by 1. */
operations[0].sem_op = 1;
/* Permit undo’ing. */
operations[0].sem_flg = SEM_UNDO;
return semop (semid, operations, 1);
}
补充:
每一个信号量中都有如下相关的值:
@ unsigned short semval;//信号量的值
@ unsigned short semzcnt;//# waiting for zero
@ unsigned short semncnt;//# waiting for increase
@ pid_t sempid;//最后一个操作信号量的进程的进程ID
...
5.2.4 信号量调试
使用 ipcs -s显示当前系统中存在的信号量集
使用 ipcrm sem semaphore_set_identifier 删除一个存在的信号量集
下面是个完整的例子,例子中,进程A向共享内存写入数据,执行 V 操作,再执行 P 操作,从共享内存读出数据,退出。进程B 中 执行 P 操作,然后从
共享内存中读出数据,再向其中写入数据。然后退出。注意:本程序应先运行A,马上在运行B.示意性的。
你还可以参考:http://blog.csdn.net/liranke/archive/2010/05/15/5595734.aspx