Linux_进程间通信之匿名管道

进程间通信

目的:

  • 数据传输:一个进程将数据发给另一个进程
  • 资源共享:多进程共享同样的资源
  • 通知事件:一个进程向另一个进程通知某事件发生,如进程终止要通知父进程
  • 进程控制:有些进程希望完全控制另一个进程的执行,如Debug进程,此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道他的状态改变

分类:

  • 管道:匿名管道pipe、命名管道
  • System V IPC:消息队列、共享内存、信号量
  • POSIX IPC:消息队列、共享内存、信号量、互斥量、条件变量、读写锁

管道:把一个进程连接到另一个进程的一个数据流称为管道

匿名管道

#include <unistd.h>
//创建一个无名管道
int pipe(int pipefd[2]);
//pipefd:文件描述附数组;pipefd[0]表示读端,pipefd[1]表示写端
//成功返回0;失败返回错误代码

调用pipe函数的进程(用户):
pipefd[1] —w---> 管道(内核) —r---> pipefd[0]

#include<iostream>
#include<stdio.h>
#include<unistd.h>
#include<cstring>
#include<cstdlib>

using namespace std;

int main()
{
	char buffer[128];
	int pipefds[2];
	int flag = pipe(pipefds);
	if(flag == -1)
	{
		perror("make pipe");
		_exit(1);
	}
	//读取键盘输入写入buffer
	while(fgets(buffer, sizeof(buffer), stdin))
	{
		int len = strlen(buffer);
		//将buffer内容写入管道
		if(write(pipefds[1], buffer, len) != len)
		{
			perror("write to pipe");
			break;
		}
		//把buffer内容置空
		memset(buffer, 0x00, sizeof(buffer));
		//从管道读的内容写入buffer
		if((len = read(pipefds[0], buffer, sizeof(buffer))) == -1)
		{
			perror("read from pipe");
			break;
		}
		//将buffer内容写入显示器
		if(write(1, buffer, len) != len)
		{
			perror("write to stdout");
			break;
		}
	}
	return 0;
}

用fork来共享管道原理
在这里插入图片描述
fork之后各自关掉不用的描述附,即关掉父进程fd[1]和子进程fd[0]

文件描述附角度理解管道
在这里插入图片描述

  • 图为一个父进程创建管道。
  • 若父进程fork出子进程,则子进程fd也连接到管道两端。
  • 父进程关闭fd[0],子进程关闭fd[1]时,父进程只写,子进程只读。

内核角度理解管道
在这里插入图片描述

#include<iostream>
#include<stdio.h>
#include<unistd.h>
#include<cstdlib>
#include<error.h>
#include<cstring>

#define ERR_EXIT(m) do{perror(m);exit(EXIT_FAILURE);}while(0)

using namespace std;

int main()
{
	int pipefd[2];
	if(pipe(pipefd) == -1)
	{
		ERR_EXIT("pipe error");
	}
	pid_t pid = fork();
	if(pid == -1)
	{
		ERR_EXIT("fork error");
	}
	if(pid == 0)
	{
		close(pipefd[0]);
		write(pipefd[1], "hello", 5);
		close(pipefd[1]);
		exit(EXIT_SUCCESS);
	}
	close(pipefd[1]);
	char buf[10] = {};
	read(pipefd[0], buf, 10);
	cout<<buf<<endl;
	close(pipefd[0]);
	return 0;
}

管道读写规则

  • 没有数据可读时
    O_NONBLOCK disable:read调用阻塞,进程暂停执行,一直等到有数据来
    O_NONBLOCK enable:read调用返回-1,errno值为EAGAIN
  • 当管道满的时候
    O_NONBLOCK disable:write调用阻塞,直到有进程读走数据
    O_NONBLOCK enable:write调用返回-1,errno值为EAGAIN
  • 如果所有管道写端对应文件描述附被关闭,则read返回0
  • 如果所有管道读端对应文件描述附被关闭,则write操作会产生信号SIGPIPE,可能导致write进程退出
  • 当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性
  • 当要写入的数据量大于PIPE_BUF时,linux将不保证写入的原子性

管道的特点

  • 只能用于具有共同祖先的进程间通信。通常一个管道由一个进程创建,然后改进程调用fork,此后父子进程就可用该管道
  • 管道提供流式服务
  • 一般的,进程退出,管道释放
  • 一般的,内核会对管道操作进行同步与互斥
  • 管道是半双工的,数据只能向一个方向流动;需要双方通信只能建立两个管道
    在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux中有多种进程通信的机制,包括管道、命名管道、信号量、消息队列、共享内存和套接字等。下面是其中几种机制的介绍和示例: 1. 管道(Pipe):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程使用。在Linux中,管道分为匿名管道和命名管道两种。其中,匿名管道只能在具有亲缘关系的进程使用,而命名管道则可以在不具有亲缘关系的进程使用。 示例代码: ```python # 创建匿名管道 import os r, w = os.pipe() # 返回读端和写端的文件描述符 # 在子进程中写入数据 pid = os.fork() if pid == 0: os.close(r) w = os.fdopen(w, 'w') w.write('Hello, parent process!') w.close() exit(0) # 在父进程中读取数据 os.close(w) r = os.fdopen(r) print(r.read()) r.close() ``` 2. 信号量(Semaphore):信号量是一种计数器,用于多进程的同步和互斥。在Linux中,信号量由一个非负整数和一个等待队列组成。 示例代码: ```python import threading # 创建信号量 semaphore = threading.Semaphore(0) # 在子线程中释放信号量 def child_thread(): print('Child thread is running...') semaphore.release() # 在主线程中等待信号量 print('Main thread is waiting...') semaphore.acquire() print('Main thread got the semaphore!') ``` 3. 共享内存(Shared Memory):共享内存是一种最快的进程通信方式,它允许多个进程访问同一块内存区域。在Linux中,共享内存需要使用shmget、shmat和shmdt等系统调用。 示例代码: ```python import os import mmap # 创建共享内存 fd = os.open('test.txt', os.O_RDWR | os.O_CREAT) os.write(fd, b'Hello, world!') size = os.path.getsize('test.txt') mem = mmap.mmap(fd, size) # 在子进程中修改共享内存 pid = os.fork() if pid == 0: mem[0:5] = b'Hi, ' mem.flush() exit(0) # 在父进程中读取共享内存 os.waitpid(pid, 0) print(mem[:]) mem.close() os.close(fd) ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值