目录
3.为什么我们子进程主动close(0/1/2),不影响父进程继续使用显示器文件呢?
一、通信
1、进程为什么要通信?
1.数据的类型
2.父进程和子进程算通信吗?
2、进程如何通信?
3、进程通信的常见方式?
二、管道
1、概念
1.管道的4种情况:
2.管道的5种特征:
2、匿名管道
1.为什么父子进程会向同一个显示器终端打印数据?
2.进程默认会打开三个标准输入输出:0,1,2 ?
3.为什么我们子进程主动close(0/1/2),不影响父进程继续使用显示器文件呢?
4.什么是管道文件?
5.管道文件的特点?
6.管道文件结构图
7.父子既然要关闭不需要的fd,那为什么要打开?
8.可以不关不需要的fd吗?
9.如果想双向通信,怎么办?
10.为什么要单向通信?
11.管道的使用(*)
12.read、write的注意点:
13.命令行中的管道符号:‘ | ’
14.管道多次创建的示意图(*)
3、命名管道
1.原理
2.匿名管道和命名管道的区别
3.怎么保证两个毫不相干的进程,打开了同一个文件呢?
4.命名管道操作 --- 系统调用篇
5.命名管道操作 --- 指令篇
三、管道的项目 --- 进程池
process_pool.cc
#include "Task.hpp"
// 父进程写,子进程读
class Channel
{
private:
int _wfd;
int _id;
public:
Channel(int wfd, int id)
: _wfd(wfd), _id(id)
{
}
void close_subprocess()
{
close(_wfd);
}
int get_wfd()
{
return _wfd;
}
int get_id()
{
return _id;
}
};
void work(int rfd);
void create_ChannelAndSubprocess(std::vector<Channel> *channels, int child_number, work_t work);
int next_channel(std::vector<Channel> &channels);
void send_command(Channel &channel, int option_task);
void ctrl_channel(std::vector<Channel> &channels);
void clean_ChannelAndSubprocess(std::vector<Channel> *channels);
int main(int argv, char* argc[])
{
std::vector<Channel> channels;
load_task();
if (argv != 2)
return -1;
int num = std::stoi(argc[1]);
// 1、创建信道和子进程
create_ChannelAndSubprocess(&channels, num, work);
// 2、通过信道控制子进程
ctrl_channel(channels);
// 3、回收管道和子进程
clean_ChannelAndSubprocess(&channels);
return 0;
}
void create_ChannelAndSubprocess(std::vector<Channel> *channels, int child_number, work_t work)
{
for (int i = 0; i < child_number; i++)
{
int pipefd[2] = {0};
int exit_code = pipe(pipefd);
if (exit_code < 0)
{
std::cout << "errno : " << exit_code << std::endl;
exit(1);
}
pid_t id = fork();
if (id == 0)
{
// child;
close(pipefd[1]);
work(pipefd[0]);
exit(0);
}
// father
close(pipefd[0]);
(*channels).emplace_back(pipefd[1], id);
}
std::cout << "创建了:" << channels->size() << "个信道和子进程" << std::endl;
}
int next_channel(std::vector<Channel> &channels)
{
static int count = 0;
int option = count;
count++;
count %= channels.size();
return option;
}
void send_command(Channel &channel, int option_task)
{
write(channel.get_wfd(), &option_task, sizeof(option_task));
}
void ctrl_channel(std::vector<Channel> &channels)
{
// 选择任务
srand(time(nullptr));
int n = task_number;
while (n -- )
{
int option_task = rand() % task.size(); // task[option_task]
// 选择信道
int option_channel = next_channel(channels); // channels[option_task]
// 发送任务
send_command(channels.at(option_channel), option_task);
sleep(1);
}
}
void clean_ChannelAndSubprocess(std::vector<Channel> *channels)
{
for (auto& channel:*channels)
{
channel.close_subprocess();
}
for (auto& channel:*channels)
{
waitpid(channel.get_id(), 0, 0);
}
}
task.hpp
#pragma once
#include <iostream>
#include <vector>
#include <string>
#include <cstring>
#include <unistd.h>
#include <cstdlib>
#include <ctime>
#include <sys/types.h>
#include <sys/wait.h>
typedef void (*task_t)();
typedef void (*work_t)(int);
const int size = 4096;
const int task_number = 7;
// 加载
void download()
{
std::cout << "This is a downlaod task!" << std::endl;
}
// 打印
void print()
{
std::cout << "This is a print task!" << std::endl;
}
// 刷新
void flush()
{
std::cout << "This is a flush task!" << std::endl;
}
std::vector<task_t> task;
void load_task()
{
task.push_back(download);
task.push_back(print);
task.push_back(flush);
}
void excute_task(int option_task)
{
if (option_task < 0 || option_task >= task.size())
return;
task.at(option_task)();
}
void work(int rfd)
{
int t = task_number;
int option_task = 0;
int n = read(rfd, &option_task, sizeof(option_task));
if (n > 0)
{
excute_task(option_task);
std::cout << "--------------------------------" << std::endl;
}
}
Makefile
process_pool:process_pool.cc
g++ $^ -o $@ -std=c++11
.PHONY:clean
clean:
rm -rf process_pool
谢谢大家!