【Linux】进程间通信

进程间通信



一、进程间通信介绍

1.1 进程间通信目的

在这里插入图片描述
在这里插入图片描述


1.2 进程间通信发展

在这里插入图片描述


1.3 进程间通信分类

在这里插入图片描述


二、管道

在这里插入图片描述


三、匿名管道

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

3.1 示例代码

代码如下(示例):

例⼦:从键盘读取数据,写⼊管道,读取管道,写到屏幕
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main( void )
{
int fds[2];
char buf[100];
int len;
if ( pipe(fds) == -1 )
perror("make pipe"),exit(1);
// read from stdin
while ( fgets(buf, 100, stdin) ) {
len = strlen(buf);
// write into pipe
if ( write(fds[1], buf, len) != len ) {
perror("write to pipe");
break;
}
memset(buf, 0x00, sizeof(buf));
// read from pipe
if ( (len=read(fds[0], buf, 100)) == -1 ) {
perror("read from pipe");
break;
}
// write to stdout
if ( write(1, buf, len) != len ) {
perror("write to stdout");
break;
}
}
}

3.2 用fork来共享管道原理

在这里插入图片描述


3.3 站在文件描述符角度-深度理解管道

在这里插入图片描述


3.4 站在内核角度-管道本质

在这里插入图片描述
所以看待管道,就如同看待文件一样!
管道的使用和文件一致


3.5 管道样例

3.5.1 测试管道读写

代码如下(示例):

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
int main(int argc, char *argv[])
{
int pipefd[2];
if (pipe(pipefd) == -1)
ERR_EXIT("pipe error");
pid_t pid;
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] = {0};
read(pipefd[0], buf, 10);
printf("buf=%s\n", buf);
return 0;
}

3.5.2 创建进程池处理任务

代码如下(示例):

// channel.cpp
#ifndef __CHANNEL_HPP__
#define __CHANNEL_HPP__
#include <iostream>
#include <string>
#include <unistd.h>
// 先描述
class Channel
{
public:
Channel(int wfd, pid_t who) : _wfd(wfd), _who(who)
{
// Channel-3-1234
_name = "Channel-" + std::to_string(wfd) + "-" + std::to_string(who);
}
std::string Name()
{
return _name;
}
void Send(int cmd)
{
::write(_wfd, &cmd, sizeof(cmd));
}
void Close()
{
::close(_wfd);
}
pid_t Id()
{
return _who;
}
int wFd()
{
return _wfd;
}
~Channel()
{
}
private:
int _wfd;
std::string _name;
pid_t _who;
};
#endif


// processpool.hpp
#ifndef __PROCESS_POOL_HPP__
#define __PROCESS_POOL_HPP__
#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <functional>
#include "Task.hpp"
#include "Channel.hpp"
// typedef std::function<void()> work_t;
using work_t = std::function<void()>;
enum
{
OK = 0,
UsageError,
PipeError,
ForkError
};
class ProcessPool
{
public:
ProcessPool(int n, work_t w)
: processnum(n), work(w)
{
}
// channels : 输出型参数
// work_t work: 回调
int InitProcessPool()
{
// 2. 创建指定个数个进程
for (int i = 0; i < processnum; i++)
{
// 1. 先有管道
int pipefd[2] = {0};
int n = pipe(pipefd);
if (n < 0)
return PipeError;
// 2. 创建进程
pid_t id = fork();
if (id < 0)
return ForkError;
// 3. 建⽴通信信道
if (id == 0)
{
// 关闭历史wfd
std::cout << getpid() << ", child close history fd: ";
for(auto &c : channels)
{
std::cout << c.wFd() << " ";
c.Close();
}
std::cout << " over" << std::endl;
::close(pipefd[1]); // read
// child
std::cout << "debug: " << pipefd[0] << std::endl;
dup2(pipefd[0], 0);
work();
::exit(0);
}
// ⽗进程执⾏
::close(pipefd[0]); // write
channels.emplace_back(pipefd[1], id);
// Channel ch(pipefd[1], id);
// channels.push_back(ch);
}
return OK;
}
void DispatchTask()
{
int who = 0;
// 2. 派发任务
int num = 20;
while (num--)
{
// a. 选择⼀个任务, 整数
int task = tm.SelectTask();
// b. 选择⼀个⼦进程channel
Channel &curr = channels[who++];
who %= channels.size();
std::cout << "######################" << std::endl;
std::cout << "send " << task << " to " << curr.Name() << ", 任务还
剩: " << num << std::endl;
std::cout << "######################" << std::endl;
// c. 派发任务
curr.Send(task);
sleep(1);
}
}
void CleanProcessPool()
{
// version 3
for (auto &c : channels)
{
c.Close();
pid_t rid = ::waitpid(c.Id(), nullptr, 0);
if (rid > 0)
{

3.6 管道读写规则

在这里插入图片描述


3.7 管道特点

在这里插入图片描述
在这里插入图片描述


四、命名管道

在这里插入图片描述

在这里插入图片描述

4.1 创建一个命名管道

在这里插入图片描述


4.2 匿名管道与命名管道的区别

在这里插入图片描述


4.3 命名管道的打开规则

在这里插入图片描述


五、system V共享内存

共享内存区是最快的IPC形式。⼀旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,
换句话说是进程不再通过执⾏进⼊内核的系统调⽤来传递彼此的数据


在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


5.1 共享内存示意图

在这里插入图片描述


5.2 共享内存数据结构

在这里插入图片描述


5.3 共享内存函数

在这里插入图片描述
在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述
在这里插入图片描述


六、system V消息队列

ipc看到同一份资源,维护成为一个队列
在这里插入图片描述

在这里插入图片描述


七、system V信号量

7.1 并发编程

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述


7.2 信号量

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述


在这里插入图片描述

在这里插入图片描述


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值