进程通信的定义及分类+信号通信案列详解

一:进程通信的原因

1):为了提高计算机系统的效率,增强计算机系统内各种硬件的并行操作能力,操作系统要求程序结构必须适应并发处理的需要,为此引入了进程。

2):由于不同的进程运行在各自不同的内存空间中,一方变量的修改另一方是无法感知到的。因此,进程之间的信息传递不可能通过变量或其它数据结构直接进行,只能通过进程间通信来完成。

二:什么是进程通信:

两个应用程序(进程)之间的交互过程称为进程通信。

三:进程通信的分类

进程通信根据交换信息量的多少和效率的高低,分为低级通信(只能传递状态和整数值)和高级通信(提高信号的通信效率,传递大量数据,减轻程序编制的复杂度),其中,高级进程通信分为三种:共享内存模式,消息传递模式,共享文件模式。

四:进程通信的基本方式:

1) 文件和记录锁定。
为避免两个进程间同时要求访问同一共享资源而引起访问和操作的混乱,在进程对共享资源进行访问前必须对其进行锁定,该进程访问完后再释放。这是UNIX为共享资源提供的互斥性保障。
2)管道。
管道一般用于两个不同进程之间的通信。当一个进程创建一个管道,并调用fork创建自己的一个子进程后, 父进程关闭读管道端,子进程关闭写管道端,这样 提供了两个进程之间数据流动的一种方式。
3)FIFO。
FIFO是一种先进先出的队列。它类似于一个管道,只允许数据的单向流动。每个FIFO都有一个名字,允许不相关的进程访问同一个FIFO。因此也成为命名管。
4) 消息队列
UNIX下不同进程之间可实现共享资源的一种机制;UNIX允许不同进程将格式化的数据流以消息形式发送给任意进程。对 消息队列具有操作权限的进程都可以使用msget完成对消息队列的操作控制。通过使用消息类型,进程可以按任何顺序读消息,或为消息安排优先级顺序。
5)信号灯。
作为 进程间通讯的一种方法,它不是用于交换大批数据,而用于 多进程之间的同步(协调对共享存储段的存取)。
6) 共享内存
通过信号灯实现存储共享(类似“红灯停、绿灯行”)

五:进程通信之信号通信 

1):信号通信分为三块内容,分别是信号的发送,信号的接收,信号的处理。信号的发送是由发送进程和内核来完成的,信号的接收和处理是由内核和接收进程来完成的。

扫描二维码关注公众号,回复: 1304628 查看本文章

2):信号的发送。信号的发送是由内核发送的,内核可以发送很多信号,但不知道发送什么信号和发给用户空间那个进程,因此发送进程要告诉内核这些信息。这就涉及到系统调用函数kill

kill函数:

函数形式:  int  kill (pid_t  pid,  int sig)

功能:告诉内核发送sig信号和发给用户空间pid进程,所需的头文件是   #include"signal.h"和#include"sys/types.h".

参数:pid是接收信号的进程,sig是信号的ID值。

返回值:成功返回0,出错则返回-1.

3):信号的接收

接收信号的进程要想收到信号,这个进程就不能结束,可以有如下三种方式来处理:第一种是睡眠函数sleep;第二种是死循环while(1);第三种是使用pause函数。

4):信号的处理

接收信号进程收到信号之后的处理方式有两种,分别是默认处理方式和自己处理方式。默认处理方式通常是终止进程或忽略该信号。接收进程如果是自己处理接收到的信号,则要吧处理信号的方法告诉内核,这涉及到signal函数

函数形式:void(  *signal(int signum,void(*handler)(int)  )(int)

功能:告诉内核自己处理那个信号和怎样处理这个信号

头文件: #include"signal.h"

参数:signum是信号的ID值,handler为收到信号后的处理方式。

返回值:函数指针    //处理方式是自己定义的一个函数,返回指向处理方式的函数指针。

六:信号通信案列详解

基于Linux的进程通信来模仿听音乐与接电话间的信息交互。

主要知识点:进程通信之信号通信(kill, signal),标准i/o(fwrite, fread, fclose),进程相关命令(ps -axj)

基本思路:

首先执行listening_music,通过while(1)循环不断模拟听音乐的过程,在这个过程中间,signal函数一直在等待monitoring_phone发过来的信号10/12,当接收到10,将flag标志位置为0,音乐暂停(依旧在while(1)循环当中,只是不再显示listening music.........),此时monitoring_phone依旧执行,且已经监听完成一次,开始模拟接听过程。当接听结束,音乐继续播放,如此,不断循环。

注:两者之间信号的交换是通过kill函数和signal函数,而传递的信号的pid值是随着每一次的编译,而不断改变的,这个问题是怎么解决的?是通过标准i/o来进行文件的保存和读取,且只需要保存一个getpid()返回的pid即可。

具体代码:

server.c

#include"stdio.h"
#include"unistd.h"
#include"signal.h"
#include"sys/types.h"
int flag=0;

void myfun(int sig)
{
	if(sig==10)
	{
		flag=1;
	}
	else if(sig==12)
	{
		flag=0;
	}
}
void listening_music()
{
	int i;
	for(i=0;i<200;i++)
	{
		while(1)
		{
			if(flag==0)
			{
				break;
		    }
		}
		printf("Listening music......i=%d\n",i);
		usleep(200000);
	}
}

void save()
{
	FILE *file=fopen("信号","w+");
    if(file==NULL)
    {
	  perror("fopen");  //即无法打开此文件,并报错
	  //exit(1);
    }
	
	int i;
	int h=getpid();
	printf("Process id is: %d\n",h);
	
	int buffer[]={0};
	buffer[0]=h;
	
	if( fwrite(buffer,sizeof(int),1,file) == EOF)
	{
		printf("文件写入错误!\n");
	}

	fclose(file);
}
int main()
{
	
	signal(10,myfun);
	signal(12,myfun);
	while(1)
	{
		save();
		listening_music();
	}
	return 0;
}

client.c

#include"stdio.h"
#include"unistd.h"
#include"signal.h"
#include"sys/types.h"

void monitoring_phone()
{
	int b=loading();
	int i,j;
	for(i=0;i<150;i++)
	{
		printf("monitoring_phone......i=%d\n",i);
		usleep(200000);
	}
	kill(b,10);   //10代表的信号即是有电话,停止音乐
	
	for(j=0;j<50;j++)
	{
		printf("processing phone......j=%d\n",j);
		usleep(200000);
	}
	kill(b,12);  //12代表的信号即是电话结束,音乐继续
}

int loading()
{
	FILE *file=fopen("信号","a+");
    if(file==NULL)
    {
	   perror("fopen");   //即无法打开此文件,并报错
	   fclose(file);
	   //exit(1);
    }
	
	int buf[]={0};
	if( fread(buf,sizeof(int),1,file) == EOF)
	{
		printf("文件写入错误!\n");
	}
	int a=buf[0];
	return a;
}

int main()
{
	while(1)
	{
		monitoring_phone();
	}
	return 0;
}


猜你喜欢

转载自blog.csdn.net/leikun153/article/details/79924899