1.一个父进程生成五个子进程且分别建立与子进程管道
①用for循环,结束条件为<5 ②father父进程每次都要离开for循环,生成下一个子进程和管道
2.#include <cassert>和#include <assert.h>的区别
assert.h
是 C 标准库的头文件,cassert
是 C++ 标准库的头文件
3.子进程进行读取
那咱就关闭写端:close(pipefd[1]),保留读端
4.父进程进行写入
那咱就关闭读端:close(pipefd[0]),保留写端
5.让父进程实现:选择让哪个进程执行哪个命令
使用pair<pid_t,int>创建键值对,实现一一对应。
vector<pair<pid_t,int> > slots;创建各个进程与命令的对应表
slots.push_back(pair<pid_t,int>(id,pipefd[1]));将进程与命令建立连接
6.让子进程等待命令
waitCommand(pipefd[0]);//如果对方不发,我们就阻塞
int waitCommand(int waitFd)
{
uint32_t command = 0;
ssize_t s=read(waitFd,&command,sizeof(command));
assert(s == sizeof(uint32_t));
return command;
}
7.uint32_t对应几个字节
4个
8.默认情况下,read是XX等待?
在默认情况下,read
函数是阻塞等待的。这意味着当调用read
函数时,如果没有数据可读取,程序将一直等待直到有数据可用或者遇到了文件结束(EOF)。
当调用
read
函数时,它会阻塞程序的执行,直到满足以下条件之一:
count
字节的数据可用:如果读取的数据长度满足count
字节,read
函数会立即返回,并将数据复制到buf
指向的缓冲区。- 文件结束(EOF):如果文件已经读取到末尾,
read
函数将返回0,表示没有更多数据可读。- 非阻塞IO(使用
O_NONBLOCK
选项):在某些情况下,可以将文件描述符设置为非阻塞模式,这样read
函数将不会阻塞并立即返回,如果没有数据可读,则返回-1,并将errno
设置为EAGAIN
或EWOULDBLOCK
。需要注意的是,对于套接字(网络套接字或UNIX域套接字)的阻塞
read
,当连接关闭时,read
函数将返回0,表示没有更多数据可读。如果要使用非阻塞IO,需要在套接字上设置相应的选项。如果需要实现非阻塞读取,可以使用
O_NONBLOCK
选项或fcntl
函数来设置文件描述符的非阻塞模式,或者使用多线程/多进程的方式来实现异步读取。
9.typedef function<void()> func,以及它的等价写法
typedef function<void()> func表示定义函数对象,等价写法是using func=function<void()>
代码实现:
Makefile:
ProcessPool:ProcessPool.cc
g++ -o $@ $^ -std=c++11 #-DDEBUG
.PHONY:clean
clean:
rm -f ProcessPool
Task.hpp
#pragma once
#include <iostream>
#include <string>
#include <unistd.h>
#include <functional>
#include <vector>
#include <unordered_map>
using namespace std;
typedef function<void()> func;//等价于 using func=function<void()>
vector<func> callbacks;
unordered_map<int,string> desc;
void readMySQL()
{
cout<<"process["<<getpid()<<"]执行访问数据库的任务" <<endl;
}
void execuleUrl()
{
cout<<"process["<<getpid()<<"]执行url解析" <<endl;
}
void cal()
{
cout<<"process["<<getpid()<<"]执行加密任务" <<endl;
}
void save()
{
cout<<"process["<<getpid()<<"]执行数据持久化任务" <<endl;
}
void load()
{
desc.insert({callbacks.size(),"readMySQL:读取数据库"});
callbacks.push_back(readMySQL);
desc.insert({callbacks.size(),"execuleUrl:进行url解析"});
callbacks.push_back(execuleUrl);
desc.insert({callbacks.size(),"cal:进行加密计算"});
callbacks.push_back(cal);
desc.insert({callbacks.size(),"save:进行数据的文件保存"});
callbacks.push_back(save);
}
void showHandler()
{
for(const auto &iter:desc)
{
cout<<iter.first<<"\t"<<iter.second<<endl;
}
}
int handlerSize()
{
return callbacks.size();
}
processPool.cc
#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <cassert>
#include <vector>
#include "Task.hpp"
#include <cstdlib>
#include <ctime>
#define PROCESS_NUM 5
using namespace std;
int waitCommand(int waitFd,bool &quit)
{
uint32_t command = 0;
ssize_t s = read(waitFd, &command, sizeof(command));
if(s == 0)
{
quit=true;
return -1;
}
assert(s == sizeof(uint32_t));
return command;
}
void sendAndWakeup(pid_t who, int fd, uint32_t command)
{
write(fd,&command,sizeof(command));
cout<<"call process"<<who<<"execute"<<desc[command]<<"through"<<fd<<endl;
}
int main()
{
load();
// vector内放置pid:pipefd键值对
vector<pair<pid_t, int>> slots;
// 先创建多个进程
for (int i = 0; i < PROCESS_NUM; i++)
{
// 创建管道
int pipefd[2] = {0};
int n = pipe(pipefd);
assert(n > 0);
(void)n;
pid_t id = fork();
assert(id != -1);
// 子进程我们让它进行读取
if (id == 0)
{
// 关闭写端
close(pipefd[1]);
// child
while (true)
{
// pipefd[0]
// 等命令
bool quit=false;
int command = waitCommand(pipefd[0],quit); // 如果对方不发,我们就阻塞
if(quit) break;
// 执行对应的命令
if (command >= 0 && command < handlerSize())
{
callbacks[command]();
}
else
{
cout << "非法command:" << command << endl;
}
}
exit(1);
}
// father,进行写入,关闭读端
close(pipefd[0]);
slots.push_back(pair<pid_t, int>(id, pipefd[1]));
}
// 父进程派发任务
srand(unsigned long)time(nullptr)^getpid()^23323123123L);//让数据更随机
while (true)
{
int select;
int command;
cout << "##############################################" << endl;
cout << "# 1.show functions 2.send command #" << endl;
cout << "##############################################" << endl;
cout << "Please Select>";
cin >> select;
if (select == 1)
showHandler();
else if (select == 2)
{
cout << "Enter Your Command>";
// 选择任务
cin >> command;
// 选择进程
int choice = rand() % slots.size();
// 把任务给指定的进程
sendAndWakeup(slots[choice].first, slots[choice].second, command);
}
}
// 关闭fd,所有的子进程都会退出
for(const auto& slot:slots)
{
close(slot.second);
}
//回收所有的子进程信息
for(const auto & slot:slots)
{
waitpid(slot.first,nullptr,0);
}
}