UNPv2:进程间通信(四) System V信号量

1概述

一般信号量分为二值信号量和计数信号量。

二值信号量:其值或为0或为1的信号量。若资源被锁住则信号量值为0,若资源可用则信号量为1.

计数信号量:其值在0和某个限制值之间的信号量。使用这些信号量在生产者-消费者问题中统计资源,信号量就是可用资源数。

Posix信号量指的是单个计数信号量,而System V信号量指的是计数信号量集。

计数信号量集:一个或多个信号量构成一个集合,其中每个信号量都是计数信号量。每个集合的信号量数存在一个限制,一般在25个数量级上。

对于系统中的每个信号量集,内核维护一个semid_ds信息结构,定义在<sys/sem.h>头文件:

struct semid_ds

{

struct ipc_perm sem_perm;

struct sem    *sem_base;

unsigned short sem_nsems;/*信号量数目*/

time_t       sem_otime;

time_t       sem_ctime;

};

sem结构是内核用于维护某个给定信号量的一组值的内部数据结构。一个信号量集的每个成员由如下这个结构描述:

struct sem

{

unsigned short semval;//信号量值

pid_t         sempid;//对信号量值执行最后一个操作的进程的ID

unsigned short semncnt;//等待信号量值增加的进程数计数

unsigned short semzcnd;//等待信号量值为0的进程数计数

};


2函数

头文件

#include <sys/sem.h>

函数

int semget(key_t key, int nsems, int flag);

参数

key:键值

nsems:该信号量集中的信号量数。如果是创建新集合(一般在服务器进程中),则必须指定nsems;如果引用一个现存的集合(一个客户进程),则将nsems指定为0.

flag:标志位,包括读写权限位(SEM_RSEM_A)和创建打开标志位(IPC_CREATIPC_CREAT|IPC_EXCL

当只有IPC_CREAT时,若不存在则创建信号量集并返回其ID;若存在,则返回其ID

当为IPC_CREAT | IPC_EXCL时,若信号量集存在则返回-1,若不存在则创建。

返回值

若成功则返回信号量ID,若出错则返回-1

功能

创建一个信号量集或访问一个已存在的信号量集


头文件

#include <sys/sem.h>

函数

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

参数

semid:信号量集标识符

semnum:信号量集中的一个信号量成员,值为0~nsems-1之间。

cmd:有10种命令,IPC_STATIPC_SETIPC_RMIDGETVALSETVAL……..

arg:该参数是可选的,是多个特定命令参数的联合。

union semun{

int  var;

struct semid_ds *buf;

unsigned short *array;

};

返回值

GETALL以外的所有GET命令都返回相应的值。其他命令返回0。出错返回-1.

功能

信号量多种操作


头文件

#include <sys/sem.h>

函数

int semop(int semid, struct sembuf semoparray[], size_t nops);

参数

semid:信号量集标识符

semoparray:操作数组

struct sembuf{

       unsigned short sem_num;//信号量成员,值为0~nsems-1

       short sem_op;//指定成员的操作,值为负数、0、正数

       short sem_flg;//0、IPC_NOWAITSEM_UNDO

};

nops:数组中操作的数量(元素个数)

返回值

若成功则返回0,若出错则返回-1

功能

自动执行信号量集合上的操作数组


3应用

信号量集示例:子进程打印字母c,父进程打印字母p

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/wait.h>

int semphore_p(int);
int semphore_v(int);

union semun
{
    int val;/* Value for SETVAL */
    struct semid_ds *buf;
    unsigned short *array;
    struct seminfo *__buf;
};

int main(void)
{
    key_t key;
    int semid;
    pid_t pid;
    int i;
    int nsems = 1;
    union semun semval;

    /*创建键值*/
    if((key = ftok("15semaphore.c", 0)) == -1)     
    {
        printf("ftok error\n");
        exit(1);
    }

    /*创建信号量集*/
    if((semid = semget(key, nsems, IPC_CREAT)) == -1)
    {
        printf("semget error\n");
        exit(1);
    }

    /*设置信号量的值*/
    semval.val = nsems;    
    if(semctl(semid, 0, SETVAL, semval) == -1)
    {
        printf("semctl error\n");
        exit(1);
    }
    
    if((pid = fork()) < 0)
    {
        printf("fork error\n");
        exit(1);
    }
    else if(pid == 0)
    {
        /*子进程:信号量加锁*/
        if(semphore_p(semid) == -1)
        {
            printf("child semphore_p error\n");
            exit(1);
        }

        printf("child start...\n");
        for (i = 0; i < 10; i++)
        {
            printf("%c", 'C');
            fflush(stdout);
            sleep(1);
        }
        printf("\nchild end...\n");

        /*子进程:信号量解锁*/
        if(semphore_v(semid) == -1)
        {
            printf("child semphore_v error\n");
            exit(1);
        }
        
        exit(0);
    }

    /*父进程:信号量加锁*/
    if(semphore_p(semid) == -1)
    {
        printf("parent semphore_p error\n");
        exit(1);
    }

    printf("parent start...\n");
    for (i = 0; i < 10; i++)
    {
        printf("%c", 'P');
        fflush(stdout);
        sleep(1);
    }
    printf("\nparent end...\n");

    /*父进程:信号量解锁*/
    if(semphore_v(semid) == -1)
    {
        printf("parent semphore_v error\n");
        exit(1);
    }        

    if(semctl(semid,0,IPC_RMID,NULL) == -1)
    {
        printf("semctl rmid error\n");
        exit(1);
    }

    waitpid(pid, NULL, 0);
    
    exit(0);
}

/*P操作,申请一个资源单位*/
int semphore_p(int semid)
{
    struct sembuf sem_buf;
    sem_buf.sem_num = 0;/*值为0,代表信号量集的第一个元素*/
    sem_buf.sem_op = -1;
    sem_buf.sem_flg = SEM_UNDO;
    if(semop(semid, &sem_buf, 1) == -1)
        return -1;

    return 0;
}

/*V操作,释放一个资源单位*/
int semphore_v(int semid)
{
    struct sembuf sem_buf;
    sem_buf.sem_num = 0;
    sem_buf.sem_op = 1;
    sem_buf.sem_flg = IPC_NOWAIT;
    if(semop(semid, &sem_buf, 1) == -1)
        return -1;

    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值