Linux 系统应用编程——进程间通信(上)

本文介绍了Linux系统中进程间通信的几种方式,重点讲解了无名管道和有名管道的特性、创建与关闭、读写操作。无名管道适用于亲缘进程间通信,而有名管道则允许无关进程间通信,具有文件系统可见性。此外,文章还提到了信号在进程间通信中的角色及其处理流程。
摘要由CSDN通过智能技术生成

       现在再Linux应用较多的进程间通信方式主要有以下几种:

1)无名管道(pipe)及有名管道(fifo):无名管道可用于具有亲缘关系进程间的通信;有名管道除具有管道相似的功能外,它还允许无亲缘关系进程使用;

2)信号(signal):信号是在软件层次上对中断机制的一种模拟,它是比较复杂的通信方式,用于通知进程某事件发生。一个进程收到一个信号与处理器收到一个中断请求处理的过程类似;

3)消息队列(message queue):消息队列是消息的链接表,包括POSIX消息队列和System V 消息队列。它克服了前两种通信方式中信息量有限的缺点。具有写权限的进程可以按照一定的规则向消息队列中添加新消息;对消息队列有读权限的进程则可以从消息队列中读取消息。

4)共享内存(shared memory):可以说这时最有效的进程间通信方式。它使得多个进程可以访问同一块内存空间,不同进程可以及时查看对方进程中对共享数据的更新。这种通信方式需要依靠某种同步机制,如互斥锁和信号量等。

5)信号量(semaphore):主要作为进程之间以及统一进程的不同线程之间的同步和互斥手段。

6)套接字(socket):这时一种使用更广泛的进程间通信机制,它可用于网络中不同主机之间的进程间通信,应用非常广泛。


管道通信

        管道是Linux 中进程间通信的一种方式,它把一个程序的输出直接连接到另一个程序的输入,Linux 的管道主要包括两种:无名管道和有名管道。

一、无名管道

      无名管道是Linux中管道通信的一种原始方法,他有如下特点:

1)只能用于具有亲缘关系的进程之间的通信(也就是父子进程或兄弟进程之间);

2)是一个单工的通信模式,具有固定的读端和写端;

3)管道也可以看成一种特殊的文件,对于它的读写也可是使用普通的read() 、write()等函数,但是它不属于任何文件系统,并且只存在于内存中;(其字节大小为0)


1、无名管道的创建与关闭

       无名管道是基于文件描述符的通信方式。当一个管道创建时,它会创建两个文件描述符:fd[0] 、fd[1] 。其中 fd[0] 固定用于读管道,而 fd[1] 固定用于写管道,如下图,这样就构成了一个单向的数据通道:


管道关闭时只需要用 close() 函数将这两个文件描述符关闭即可。


2、管道创建函数

      创建管道可以通过 pipe() 来实现,其语法如下:

所需头文件 #include <unistd.h>
函数原型 int pipe(int fd[]);
函数传入值 fd :包含两个元素的整型数组,存放管道对应的文件描述符
函数返回值 成功:0
出错:-1

3、管道读写说明

       用pipe() 函数创建的管道两端处于一个进程中。由于管道主要是用于不同进程间的通信,通常是先创建一个管道,再调用 fork () 函数创建一个子进程,该子进程会继承父进程所创建的管道。

         需要注意的是,无名管道是单工的工作方式,即进程要么只能读管道,要么只能写管道。父子进程虽然都拥有管道的读端和写端,但是只能使用其中一个(例如,可以约定父进程读管道,而子进程写管道)。这样就应该把不使用的读端或写端文件描述符关闭。


例如:如果将父进程的写端 fd[1] 和子进程的读端 fd[0] 关闭。此时,父子进程之间就建立了一条“子进程写入 父进程读取”的通道。同样,也可以关闭父进程的 fd[0] 和子进程的fd[1] ,这样就可以建立一条“父进程写入子进程读取”的通道。另外,父进程也可以创建 多个子进程,各个子进程都继承了管道的fd[0] 和 fd[1] ,这样就建立子进程之间的数据通道。


4、管道读写注意:

1)只有管道的读端存在时,向管道写入数据才有意义,否则,向管道中写入数据的进程将收到内核传来的 SIGPIPE 信号 (通常为Broken Pipea错误)。

2)向管道写入数据时,Linux 将不保证写入的原子性 , 管道缓冲区只要有空间,写进程就会试图向管道写入数据。如果管道缓冲区已满,那么写操作将一直阻塞。

3)父进程在运行时,它们的先后次序必不能保证。为了确保父子进程已经关闭了相应的文件描述符,可在两个进程中调用 sleep() 函数,当然,用互斥和同步会更好;


下面是一个实例:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

int pid,pid1,pid2;

int main(int argc, const char *argv[])
{
	int fd[2];
	char outpipe[100],inpipe[100];

	if(pipe(fd) < 0)
	{
		perror("pipe error!");
		return -1;
	}

	if((pid1 = fork()) < 0)
	{
		perror("fork pid1 error");
		return -1;
	}
	else if(pid1 == 0)
	{
		printf("Child1's pid is %d\n",getpid());
		close(fd[0]);
		strcpy(outpipe,"Child 1 is sending a message!");
		if(write(fd[1],outpipe,50) == -1)
		{
			perror("Child 1 write to outpipe error");
			return -1;
		}
		exit(0);
	}
		
	if((pid2 = fork()) < 0)
	{
		perror("fork pid2 error");
		return -1;
	}
	else if(pid2 == 0)
	{
	
  • 14
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值