SYSTEM V IPC——信号量笔记

12 篇文章 0 订阅

一、概念

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值