IPC笔记之System V信号量

1、概述:System V信号量用三个函数,semget,semop,semctl,分别是信号量集的夺取,操作,控制。其操作对象是信号量集合,semop操作的集合中,这些对象要么全部成功,要么全都不成功。

2、信号量的销毁,因为System V信号量是内核持久性的,也就是说销毁方式有两种,要么在进程中显式销毁,要么只有当内核关闭时才销毁。

3、内核中与信号量有关的数据结构。

内核中维持一份全局的struct semid_ds数组,semid_ds是信号量集合的结构。semget函数返回这个信号量集合在数组中的小标。

struct semid_ds
{
    struct ipc_perm sem_perm;  //该信号量集合的操作许可权限
    struct sem *sem_base;    //该数组的元素是:该集合包含的信号量的结构。
    ushort sem_nsems;   //sem_base数组的个数
    time_t sem_otime;  //最后一次成功修改该信号量数组的时间。
    time_t sem_ctime;  //成功创建的时间
};

struct sem
{
    ushort semval;  //信号量的当前值
    short sempid;  //最后一次返回该信号量的进程的id号
    ushort semncnt; //等待semval大于当前值的进程的个数
    ushort semzcnt; // 等待semval变成0的进程的个数
};

4、int shmget(key_t key, int nsems, int flag); 返回值是信号量标示符。

key: key_t是int型的,这个是一个整数,要保证内核唯一性。
nsems:该集合包含的信号量的个数。
flag:创建的权限, 可以使一些读写权限与:IPC_CREAT ( | IPC_EXCL )的按位或。

当该函数成功时,linux内核中的semval值为0,但是该值的初始化没有可移植性(就是说不能保证所有系统都能初始化该值)

这个函数的作用:创建或者打开信号量集。

5、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时才返回。

6、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结构。

7、例子1:PV原语操作:

int sem_id = 0; /* semget的返回值,全局 */
#define MUTEX 0 /* 用于返回临界区的信号量在集合中的序数 */
#define NUM_SEM 1 /* 集合中信号量的个数 */
#define SEM_KEY 0x11223344 /*保证内核中的唯一性 */

void P(int sem_num)
{
    struct sembuf sem;
    sem.sem_num = MUTEX;
    sem.sem_op = -1;
    sem.sem_flg = 0;
    
    if( -1 == semop(sem_id, &sem, 1) )
    {
         /* 错误处理 */
    }
}


void V(int sem_num)
{
    struct sembuf sem;
    sem.sem_num = MUTEX;
    sem.sem_op = 1;
    sem.sem_flg = 0;
    
    if( -1 == semop(sem_id, &sem, 1) )
    {
         /* 错误处理 */
    }
}

主函数:

int main()
{
    ...
    int semid;
    ....
    semid = semget(SEM_KEY, 0, 0); /* panduan 判断该型号量组是否已经存在 */
    if( -1 == semid )
    {
        semid = semget(SEM_KEY, NUM_SEM, IPC_CREAT | IPC_EXCL | 0666);
        if( -1 == semid)
        {
            /* 错误处理 */
        }
        else
        {
           semctl(sem_id, MUTEX, SETVAL, 1); /* 初始值为1。错误处理略 */
        }
    }

    ...
    P(MUTEX);
    /* 临界区代码段 */
    V(MUTEX);
    ...
}

你可能感兴趣的:(数据结构,c,struct,cmd,System,linux内核)