信号量的实例

例题:

进程 a 和进程 b 模拟访问打印机,进程 a 输出第一个字符‘ a’表示开始使用打印
机,输出第二个字符‘ a’表示结束使用, b 进程操作与 a 进程相同。(由于打印机同一时刻
只能被一个进程使用,所以输出结果不应该出现 abab)

 信号量使用的函数:

1.int semget(key_t key, int nsems, int semflg);

该函数的作用是创建一个新的信号量或者是获取一个信号量。

key的作用是一个整数值,不相关的进程可以通过他访问同一个信号量。

nsems的是需要信号量的数目,几乎总是取1

semflg类似于文件的访问权限。

2. int semop(int semid, struct sembuf *sops, unsigned nsops);

 该函数的作用是来改变信号量的值。

semid是第一个函数返回的信号量描述符,类似于文件描述符。

sops是指向了一个结构体:

struct  sembuf

{

short  sem_num;   //信号量编号,一般取0

short  sem_op;   //信号量在操作中需要改变的数值,也就是pv操作

short sem_flg;  //最后一个成员通常被设置为SEM_UNDO,使得操作系统跟踪当前进程的信号量修改情况,如果进程在没有使用该信号量的情况下终止掉,那么操作系统会自动释放该进程持有的信号量。

}

nsops是要执行的信号量操作的数量

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

 第一个参数semid是返回的信号量描述符

semnum是信号量的编号,

cmd通常有两个最常用的值,SETVAL,IPC_RMID,SETVAL表示把信号量初始化一个已知的值,IPC_RMID表示删除无需再使用的信号量。

 下面通过例题的代码来理解:

SEM.h代码

#include<stdio.h>
#include<sys/sem.h>
#include<sys/ipc.h>
#include<sys/types.h>
#include<iostream>
#include<unistd.h>
using namespace std;

static int semid;
void InitSem();
void Sem_p();
void Sem_v();
void Sem_destroy();

 这段代码将pv操作封装为函数,便于程序进行调用。头文件unistd是sleep函数会使用到

 SEM.cpp代码

#include "SEM.h"
union semun 
{
    int val;
};
void  InitSem()
{  
    semid = semget(0x14,1,IPC_CREAT|IPC_EXCL|0600);
    if (semid != -1)
    {
        cout<<semid<<endl;
        union semun t;
        t.val = 1;
        if(semctl(semid, 0, SETVAL, t) == -1)
        {
           cout<<"Error"<<endl;
            exit(0);
        }
    }
    else
    {
        semid = semget(0x14, 1, 0600);
        cout<<semid<<endl;
    }
    
}


void Sem_p()
{
    struct sembuf semops;
    semops.sem_num = 0;
    semops.sem_op = -1;
    semops.sem_flg = SEM_UNDO;
    if(semop(semid, &semops, 1) == -1)
    {
        cout<<"p error"<<endl;
        exit(0);
    } 
}
void Sem_v()
{
    struct sembuf semops;
    semops.sem_num = 0;
    semops.sem_op =  1;
    semops.sem_flg = SEM_UNDO;
    if(semop(semid, &semops, 1) == -1)
    {
        cout<<"v error"<<endl;
        exit(0);
    } 
}
void Sem_destroy()
{
     if(semctl(semid, 0, IPC_RMID) == -1)
        {
           cout<<"destory Error"<<endl;
            exit(0);
        }
}

 在初始化时需要注意的问题:

首先,我们需要给信号量赋初始值,初始值应该为1,因为最开始的信号量需要被拿到

当判断是否为第一次使用该信号量时可以用两个参数IPC_CREAT|IPC_EXCL,如果为新创建的将信号量赋初始值并返回信号量描述符,不是新创建的则返回该信号量的描述符。

 a.cpp代码

#include "SEM.h"
int main()
{
    InitSem();
    int size = 3;
   while(size--)
   {
        Sem_p();
        cout<<"a"<<endl;
        cout<<"a"<<endl;
        cout<<"a"<<endl;
        cout<<"a"<<endl;
        Sem_v();
        sleep(3);
   }
}

 尽量不要将初始化sem函数放到while循环里。

b.cpp代码

#include "SEM.h"
int main()
{
    InitSem();
    int size = 3;
   while(size--)
   {
        Sem_p();
        cout<<"b"<<endl;
        cout<<"b"<<endl;
        cout<<"b"<<endl;
        cout<<"b"<<endl;
        Sem_v();
        sleep(3);
   }
   
}

通过g++ -o  a a.cpp SEM.cpp编译成a程序和b程序,运行结果如下图:

 在结果中a打印时,b不会打印。达到了题目的要求。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值