Linux进程间通信(上)

其余相关内容可参考个人博客

简介

**进程间通信(IPC,InterProcess Communication)**是指在不同进程之间传播或交换信息。

IPC的方式通常有管道(包括无名管道和命名管道)、信号、消息队列、信号量、共享内存、套接字。
其中信号的介绍可查看该文《Linux信号》

本文重点介绍管道的概念以及使用方式。

无名管道

概念

最基本的进程间通信方式,从本质上说,管道是一种特殊的文件,存在于内存中,但是它没有名字,只能用于有亲缘关系的进程间(fork)。

实现机制

管道是由内核管理的一个缓冲区,它的一端连接一个进程的输出,另一端连接一个进程的输入。管道的缓冲区不需要很大,它被设计为环形的数据结构,当两个进程都终止后,管道的生命周期也会被结束。

特点

  1. 半双工,数据只能在一个方向上流动,若要双向通信,需要建立两个管道
  2. 只能在具有公共祖先的进程之间使用,通常是fork的父子进程之间使用管道通信
  3. 管道中的数据遵循先入先出的原则
  4. 管道所传送的数据是无格式的,这要求管道的读出方与写入方必须事先约定好数据的格式
  5. 管道不是普通的文件,不属于某个文件系统,其只存在于内存中,对应一块缓冲区,不同系统大小不一定相同
  6. 管道数据被读走后抛弃,为了释放空间以便写更多数据

读写规则

  1. 阻塞性:

    • 默认用read函数读数据是阻塞(无数据时)的,write函数也是阻塞的(当管道满了时)
    • 可通过functl来改变阻塞特性,如
      funtl(fd,F_SETFL,0);设为阻塞
      funtl(fd,F_SETFL,0_NOBLOCK);设为非阻塞
  2. 退出:

    • 当写一个读端口已被关闭的管道时,写进程会收到SIGPIPE信号(默认退出,若从信号处理函数返回后则write函数出错返回,errno=EPIPE)
    • 当读一个写端口已被关闭的管道时,在所有数据都被读取后, read返回0,以指示达到了文件结束处

函数

int pipe(int pipefd[2]);
功能:创建无名管道
参数:pipefd返回两个管道的文件描述符,fd[0]用于读,fd[1]用于写
返回值;成功返回0,失败返回-1,原因保存在errno中

常用方式如下:

代码如下:

int
main(int argc, char *argv[])
{
   int pipefd[2];
   pid_t cpid;
   char buf;

   if (argc != 2) {
	   fprintf(stderr, "Usage: %s <string>\n", argv[0]);
	   exit(EXIT_FAILURE);
   }

   if (pipe(pipefd) == -1) {
	   perror("pipe");
	   exit(EXIT_FAILURE);
   }

   cpid = fork();
   if (cpid == -1) {
	   perror("fork");
	   exit(EXIT_FAILURE);
   }

   if (cpid == 0) {    /* Child reads from pipe */
	   close(pipefd[1]);          /* Close unused write end */

	   while (read(pipefd[0], &buf, 1) > 0)
		   write(STDOUT_FILENO, &buf, 1);

	   write(STDOUT_FILENO, "\n", 1);
	   close(pipefd[0]);
	   _exit(EXIT_SUCCESS);

   } else {            /* Parent writes argv[1] to pipe */
	   close(pipefd[0]);          /* Close unused read end */
	   write(pipefd[1], argv[1], strlen(argv[1]));
	   close(pipefd[1]);          /* Reader will see EOF */
	   wait(NULL);                /* Wait for child */
	   exit(EXIT_SUCCESS);
   }
}


命名管道(FIFO)

与无名管道的区别

  1. 不相关的进程之间也能交换数据

  2. 当使用FIFO的进程退出后,FIFO文件将继续保存在文件系统中以便以后使用

注意:创建命名管道一定要用指定函数创建,不能新建一个文件,因为命名管道是特殊的文件,如果对管道文件进行复制,会变成普通文件,不具有管道的特点

读写规则

  1. 阻塞性:

    • 一般情况中(open时未指定O_NOBLOCK),当你用只读/只写方式打开FIFO的时候会阻塞,直到其他进程用只写/只读方式打开该FIFO
    • 如果指定了O_NOBLOCK,则只读打开立即返回。但是,如果没有进程已经为读而打开一个FIFO,那么只写打开将出错返回,其errno是ENXIO。
  2. 退出:

    • 类似于管道,若写一个尚无进程为读而打开的FIFO,则产生信号SIGPIPE。
    • 若某个FIFO的最后一个写进程关闭了该FIFO,则将为该FIFO的读进程产生一个文件结束标志

函数

int mkfifo(const char *pathname, mode_t mode);
功能:该函数创建一个命名管道的特殊文件pathname,mode指定了FIFO的读写权限(例如0777)
返回值:成功返回0,失败返回-1,失败原因保存在errno


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值