进程间通信——信号量及ipcs/ipcrm 介绍

1.信号量描述

信号量是用来同步进程的(即控制进程的执行),是一个特殊的变量,一般取正数值。它的值代表允许访问的资源数目。获取资源时,需要对信号量的值进行原子减一,该操作被称为 P 操作。当信号量值为 0 时,代表没有资源可用,P 操作会阻塞。释放资源时,需要对信号量的值进行原子加一,该操作被称为 V操作。信号量主要用来同步进程。信号量的值如果只取 0,1,将其称为二值信号量。如果信号量的值大于 1,则称之为计数信号量
临界资源:同一时刻,只允许被一个进程或线程访问的资源
临界区:访问临界资源的代码段

2.信号量使用

2.1操作信号量的接口介绍:

#include <sys/sem.h>
#include <sys/types.h>
#include <sys/ipc.h>
/*
semget()创建或者获取已存在的信号量
semget()成功返回信号量的 ID, 失败返回-1
key:两个进程使用相同的 key 值,就可以使用同一个信号量
nsems:内核维护的是一个信号量集,在新建信号量时,其指定信号量集中信号量的个数
semflg 可选: IPC_CREAT IPC_EXCL
*/
int semget(key_t key, int nsems, int semflg);




/*
semop()对信号量进行改变,做 P 操作或者 V 操作
semop()成功返回 0,失败返回-1
nsops是信号量个数
struct sembuf
{
	unsigned short sem_num; //指定信号量集中的信号量下标
	short sem_op; //其值为-1,代表 P 操作,其值为 1,代表 V 操作
	short sem_flg; //SEM_UNDO
};
*/
int semop( int semid, struct sembuf *sops, unsigned nsops);




/*
semctl()控制信号量
semctl()成功返回 0,失败返回-1
cmd 选项: SETVAL //将val的值同步到信号量上
		  IPC_RMID
union semun//信号量下标 
{
	int val;
	struct semid_ds *buf;
	unsigned short *array;
	struct seminfo *_buf;
};
*/
int semctl( int semid, int semnum, int cmd, ...);

2.2封装信号量的接口:

sem.h 的代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<assert.h>
#include<sys/sem.h>

union semu{int val};

void sem_init();//创建并初始化,或者获取已有的信号量id
void sem_p();//p操作,信号量减一
void sem_v();//v操作,信号量加一
void sem_destroy();//销毁信号量

sem.c代码如下:

#include"sem.h"

static int  semid = -1;

void sem_init()
{
    semid = semget((key_t)1234,1,IPC_CREAT|IPC_EXCL|0600);
    if(semid == -1)//信号量已经存在
    {
        semid = semget((key_t)1234,1,0600);
    }
    else//信号量不存在,信号量被创建,在这里初始化信号量
    {
        union semun a;
        a.val = 1;
        if(semctl(semid,0,SETVAL,a)==-1)
        {
            perror("semctl error");
        }
    }
}

void sem_p()
{
    struct sembuf buf;
    buf.sem_num = 0;
    buf.sem_op = -1;//P
    buf.sem_flg = SEM_UNDO;
    if(semop(semid,&buf,1)==-1)
    {
        perror("semop P error");
    }
}


void sem_v()
{
    struct sembuf buf;
    buf.sem_num = 0;
    buf.sem_op = 1;//V
    buf.sem_flg = SEM_UNDO;
    if(semop(semid,&buf,1)==-1)
    {
        perror("semop V error");
    }
}

void sem_destroy()
{
    if(semctl(semid,0,IPC_RMID) == -1)
    {
        perror("semtcl del error");
    }
}

记不住怎么封装的也没关系,一般我们使用时,都是封装好的,我们只要知道怎么用信号量PV操作控制进程就好。

2.3例题演示:

例题(1):进程 a 和进程 b 模拟访问打印机,进程 a 输出第一个字符‘a’表示开始使用打印机,输出第二个字符‘a’表示结束使用,b 进程操作与 a 进程相同。(由于打印机同一时刻只能被一个进程使用,所以输出结果不应该出现 abab),如图所示:
在这里插入图片描述
a.c代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#include<unistd.h>
#include"sem.h"

int main()
{
    sem_init();
    for(int i = 0; i < 5; i++)
    {
        sem_p();
        printf("a start\t");
        sleep(3);
        printf("a end\n");
        sem_v();
        sleep(3);
    }
    sleep(10);
    sem_destroy();
    exit(0);
}

a.c最后sleep(10)是为了使a程序最后结束,这样可以在a程序里销毁信号量。
b.c代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#include<unistd.h>
#include"sem.h"

int main()
{
    sem_init();
    for(int i = 0; i < 5; i++)
    {
        sem_p();
        printf("b start\t");
        sleep(3);
        printf("b end\n");
        sem_v();
        sleep(3);
    }
    exit(0);
}

运行结果:
在这里插入图片描述
可以发现,由于打印机要求只有一个,所以a使用完打印机,b或者a才能继续使用打印机,不可能a和b同时使用打印机的。

(2)例题2:有一个空间,要求A进程先向里面写数据,B进程再从里面读数据,然后A进程再写…
分析1:一个信号量情况如下:
在这里插入图片描述
一眼看去发现没什么问题,但是仔细思考发现并没有对A写入数据进行控制,A写入数据不受信号量控制,A写完仍可以写。我们要求是A写完之后,B读完,A才可以再次写入的。
所以不可行。
分析2:两个信号量:
一个信号量限制A写入,一个信号量限制B读取
如下图:
在这里插入图片描述

3.ipcs/ipcrm 介绍

ipcs 可以查看消息队列、共享内存、信号量的使用情况,使用 ipcrm 可以进行删除操作。
如果我们将a.c程序中的销毁信号量的操作去掉,那么我们创建的信号量就没有销毁。a.c代码如下。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#include<unistd.h>
#include"sem.h"

int main()
{
    sem_init();
    for(int i = 0; i < 5; i++)
    {
        sem_p();
        printf("a start\t");
        sleep(3);
        printf("a end\n");
        sem_v();
        sleep(3);
    }
    exit(0);
}

运行完a和b程序后,由于程序里没有对信号量进行销毁,所以我们创建的信号量仍然存在。可以用指令ipcs查看。
以下是运行完a和b程序后用指令ipcs查看的信号量信息:
在这里插入图片描述
key值是16进制,换成10进制,就是我们程序中设置的key值1234。
可以用指令ipcrm + -s + semid指令销毁信号量。
在这里插入图片描述
ipcrm -m是对共享内存用的;
ipcrm -q是对消息队列弄的;

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孟小胖_H

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值