Linux---进程通信(六)---IPC通信之信号灯

系列文章目录

文章一: Linux—进程通信(一)—进程通信概述
文章二: Linux—进程通信(二)—管道
文章三: Linux—进程通信(三)—信号通信
文章四: Linux—进程通信(四)—IPC通信之共享内存
文章五: Linux—进程通信(五)—IPC通信之消息队列
文章六: Linux—进程通信(六)—IPC通信之信号灯


前言

本文主要讲解了IPC通信的对象之一-------信号灯
具体讲解了信号灯的各种操作函数
同时给出了用C语言编写的进程通信的实例


一、信号灯

1.信号灯是什么?

信号灯是多个信号量的一个集合,是在内核空间中被创建的用于进程间通信的一个IPC对象。

2.什么是信号量?

信号量(semaphore)的数据结构为一个值和一个指针,指针指向等待该信号量的下一个进程。信号量的值与相应资源的使用情况有关。当它的值大于0时,表示当前可用资源的数量;当它的值小于0时,其绝对值表示等待使用该资源的进程个数。注意,信号量的值仅能由PV操作来改变。

3.什么是P操作和V操作?

P(S):

1.将信号量S的值减1,即S=S-1;
2.如果S>=0,则该进程继续执行;否则该进程置为等待状态,排入等待队列。

V(S):

1.将信号量S的值加1,即S=S+1;
2.如果S>0,则该进程继续执行;否则释放队列中第一个等待信号量的进程。

PV操作的意义:

我们用信号量及PV操作来实现进程的同步和互斥。PV操作属于进程的低级通信。

二、信号灯的使用

1.信号灯的操作函数

信号灯的创建函数

函数原型:

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

所需头文件:

#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>

函数功能:

在内核空间中创建一个信号灯

函数参数:

1.key:和信号灯关联的key值
2.nsems:信号灯中包含的信号量的个数
3.semflg:信号灯集的访问权限

函数返回值:

1.成功返回信号灯集的ID
2.出错返回-1

信号灯创建函数的实例

#include<signal.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
int main()
{
	int semid;
	semid=semget(IPC_PRIVATE,3,0777);
	if(semid<0)
	{
		printf("create semaphore failure\n");
		return -1;
	}
	printf("create semaphore success shmid=%d\n",semid);
	system("ipcs -s");
	return 0;
}

执行结果:
在这里插入图片描述

信号灯的控制函数

函数原型:

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

所需头文件:

#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>

函数功能:

1.将内核空间中的信号灯删除,释放空间
2.获取和设置信号灯集中具体编号信号量的值

函数参数:

1.msqid:信号灯的ID
2.semnum:要修改的信号量在信号灯集中的编号
3.cmd:
	(1)GETVAL:获取该编号信号量的值
	(2)SETVAL:设置该编号信号量的值
	(3)IPC_RMID:从系统中删除信号灯集合
4.union semun:
	(1)当cmd选择了IPC_RMID后,可以是NULL也可以是
	(2)当cmd选择了其它两个参数,该参数是

union semun的结构:

union semun
{
	int val;
	struct semid_ds *buf;
	unsigned short *array;
	struct seminfo *_buf
};

函数返回值:

1.成功返回0
2.失败返回-1

信号灯的操作函数(P/V操作)

函数原型

int semop(int semid,struct sembuf *opsptr,size_t nops);

所需头文件:

#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>

函数参数:

1.semid:信号灯集的ID
2.struct sembuf:操作信号灯信号量的信息
3.nops:要操作的信号灯集信号量的个数

struct sembuf的数据结构:

struct sembuf
{
	short sem_num;//要操作信号量的编号
	short sem_op;
	//0:等待,直到信号量的值变为0
	//1:释放资源,V操作
	//-1:分配资源,P操作
	short sem_flg;
	//0:阻塞
	//IPC_NOWAIT:非阻塞
	//SEM_UNDO:撤销操作
}

函数返回值:

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

三、用信号灯实现两个无亲缘关系的进程之间的先后运行控制

进程1后运行
进程1的C语言代码:

#include<signal.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
int main()
{
	int i;
	union semun mysemun;
	struct sembuf mysembuf;
	int semid;
	int key;
	key=ftok("./a.c","a");
	if(key<0)
	{
		printf("create key failure\n");
		return -1;
	}
	printf("create key success\n");
	semid=semget(key,3,IPC_CREAT|0777);
	if(semid<0)
	{
		printf("create semaphore failure\n");
		return -1;
	}
	printf("create semaphore success shmid=%d\n",semid);
	system("ipcs -s");
	
	mysembuf.sem_num=0;
	mysembuf.sem_flg=0;
	for(i=0;i<10;i++)
	{
		usleep(100);
		printf("this is main fun i=%d\n",i);
	}
	mysembuf.sem_op=1;
	semop(semid,&mysembuf,1);
	
	while(1);
	return 0;
}

进程2先运行
进程2的C语言代码:

#include<signal.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
int main()
{
	int i;
	union semun mysemun;
	struct sembuf mysembuf;
	int semid;
	int key;
	key=ftok("./a.c","a");
	if(key<0)
	{
		printf("create key failure\n");
		return -1;
	}
	printf("create key success\n");
	semid=semget(key,3,IPC_CREAT|0777);
	if(semid<0)
	{
		printf("create semaphore failure\n");
		return -1;
	}
	printf("create semaphore success shmid=%d\n",semid);
	system("ipcs -s");

	mysemun.val=0;
	semctl(semid,0,SETVAL,mysemun);
	
	mysembuf.sem_num=0;
	mysembuf.sem_flg=0;


	mysembuf.sem_op=-1;
	semop(semid,&mysembuf,1);
	for(i=0;i<10;i++)
	{
		usleep(100);
		printf("this is main fun i=%d\n",i);
	}
	while(1)
	return 0;
}

注意:

运行时先运行进程2,再运行进程1可以看到效果。
因为对信号灯的初始化在进程2中,同时进程2会等待进程1运行完,故可以看到效果

执行效果:

虽然进程2先打开,但是进程1先打印语句,进程2后打印语句

总结

到这里关于进程通信的系列文章已经结束。
由于笔者是新手,介绍的不对不妥的地方请读者包含并指正。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

SigmaBull

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

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

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

打赏作者

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

抵扣说明:

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

余额充值