SYSTEM V IPC——信号量笔记

来源:互联网 发布:索尼自家应用商店软件 编辑:程序博客网 时间:2024/05/21 17:28

一、概念

system v的信号量实质是一个计数器,用于多进程对共享数据对象的访问。

二、工作流程

为了获得共享资源,进程需要执行下列操作:

1.测试控制该资源的信号量

2.若此信号的值为正,则进程可以使用该资源,并对该信号量的值减1,表示消耗了一个资源单位。至第三步。

   若此信号量的值为0,则进入休眠状态,直至信号量大于0。进程被唤醒后,返回至第一步。

3.当进程使用完该资源以后,需要释放一个信号量,即对这个信号量的值加1操作。如果有进程正在休眠等待此信号量,则唤醒他们。

备注:为了正确的实现信号量,信号量值的测试、加1、减1操作是原子操作。所以,信号量通常是在内核实现的。

三、相关函数

1.semget

获得一个信号量集ID

#include <sys/sem.h>

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

key是个什么东西?

nsems表示这个信号量集里面包含的信号量数

flag表示属性,第一次创建用IPC_CREAT

成功返回信号量ID,错误返回-1

2.semctl

设置初值或者删除等操作

int semctl(int semid, int semnum, int cmd, ...);

semid是信号量ID,就是semget的返回值;

semnum表示信号量集中的第几个信号量(0 <= semnum <= nsems )

cmd是控制指令:IPC_STAT、IPC_SET(设置初值)、IPC_RMID(删除信号量集)、GETVAL、SETVAL、GETALL……

...表示一个枚举,semun

返回值:除GETALL以外的GET命令的返回相应的值,其他成功0,失败-1

union semun

{

int val;

struct semid_ds *buf;

unsigned short *array;

};

3.semop

加1或减1操作

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

semid为信号量ID

semoparray[]为struct sembuf 型结构体指针

nops是要操作的信号量个数

返回值:成功0,失败-1

struct sembuf

{

unsigned short sem_num;//要操作的第几个信号量

short sem_op;//1 or -1

short sem_flg;//SEM_UNDO

}

四、例程(单个信号量)

#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/sem.h>#include "semun.h"static int set_semvalue(void);static void del_semvalue(void);static int semaphore_p(void);static int semaphore_v(void);static int sem_id;int main(int argc, char *argv[]){    int i;    int pause_time;    char op_char = 'O';    srand((unsigned int)getpid ());    sem_id = semget((key_t)1234,1,0666|IPC_CREAT);    if(argc >1 )    {        if(!set_semvalue ())        {            fprintf (stderr,"Failed to initialize semaphore\n");            exit(EXIT_FAILURE);        }        op_char ='X';        sleep(2);    }    for(i =0 ; i < 10; i++)    {        if(!semaphore_p ())exit(1);        printf("%c",op_char);fflush(stdout);        pause_time = rand() % 3;        sleep(pause_time);        printf("%c",op_char);fflush(stdout);        if(!semaphore_v ())exit (1);        pause_time = rand() % 2;        sleep(pause_time);    }    printf("\n%d - finished\n",getpid());    if(argc >1)    {        sleep(10);        del_semvalue ();    }    exit(0);}static int set_semvalue (void){    union semun sem_union;    sem_union.val = 1;<span style="white-space:pre"></span>//初始值设为1个资源单位    if(semctl (sem_id, 0, SETVAL, sem_union)==-1)return (0);    return (1);}static void del_semvalue (void){    union semun sem_union;    if(semctl(sem_id, 0, IPC_RMID, sem_union)==-1)        printf(stderr, "Failed to del semaphore.\n");}static int semaphore_p (void){    struct sembuf sem_b;    sem_b.sem_num = 0;    sem_b.sem_op = -1;    sem_b.sem_flg = SEM_UNDO;    if(semop(sem_id, &sem_b, 1)==-1)    {        fprintf(stderr, "semaphore_p failed.\n");        return 0;    }    return 1;}static int semaphore_v (void){    struct sembuf sem_b;    sem_b.sem_num = 0;    sem_b.sem_op = 1;    sem_b.sem_flg = SEM_UNDO;    if(semop(sem_id, &sem_b, 1)==-1)    {        fprintf(stderr, "semaphore_v failed.\n");        return 0;    }    return 1;}
添加了一个自定义的头文件semun.h:

#if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)    /* union semun is defined by including <sys/sem.h> */#else    /* according to X/OPEN we have to define it ourselves */    union semun {        int val;                    /* value for SETVAL */        struct semid_ds *buf;       /* buffer for IPC_STAT, IPC_SET */        unsigned short int *array;  /* array for GETALL, SETALL */        struct seminfo *__buf;      /* buffer for IPC_INFO */    };#endif

运行程序:

#./sem 1 &

#./sem &

结果:XXXXOOXXXXXXOOOOOOXXOOXXOOXXXXXXOOO

解释:第一次执行sem程序,申请了一个信号量集,第二次运行的sem程序,直接访问该信号量集。二者交替打印,因为信号量的存在,而初始值设为1个资源单位,所以‘X’或‘O’必定是成对出现的。



0 0
原创粉丝点击