陈村大良网站建设,wordpress增加用户权限,互联网装修公司加盟,个人可以做行业网站吗文章目录 前言一、匿名管道1.管道原理2.管道的四种情况3.管道的特点 二、命名管道1. 特点2.创建命名管道1.在命令行上2.在程序中 3.一个程序执行打开管道并不会真正打卡 三、进程池简易实现1.makefile2.Task.hpp3.ProcessPool.cpp 前言
一、匿名管道
#include unistd.hunistd.h
功能:创建一无名管道
原型
int pipe(int fd[2]);
参数
fd文件描述符数组,其中fd[0]表示读端, fd[1]表示写端
返回值:成功返回0失败返回错误代码1.管道原理 本质是先让不同的进程看到同一份资源也就是两个进程都能对管道文件的缓冲区进行操作 这里我们pipe的时候会使用两个文件描述符这两个文件描述里面存的file结构体是同一个也就是管道文件的file结构体file结构体中存储有inode以及系统缓冲区此时fork一个子进程子进程有着和父进程一样的结构 这里有一个非常重要的点虽然子进程有着自己的进程地址空间也有着自己存储file结构体的指针数组但是其数组里面的内容是和父进程一样的也就是子进程里面pipe对应的文件描述符位置指向的file结构体管道文件是同一个至此我们父子进程就看到了同一个资源可以利用这个资源进行通信
两个不同的进程打开同一份文件的时候在内核中操作系统只会打开一个
2.管道的四种情况 1.读写端正常管道如果为空读端就要阻塞 读写端正常管道如果被写满写端就要阻塞 2.读端正常读写端关闭读端就会读到0表明读到了管道文件的结尾不会被阻塞如果我们打印读端读到的内容显示器会一直显示0 3.写端正常写入读端关闭操作系统会杀掉此时正在写入的进程通过信号来杀掉 4.因为操作系统不会做低效浪费的事情我读端都不读了你写入再多数据到一个管道里面有什么用因为管道不占用磁盘内存所以程序结束后就没有管道的存在了。 当要写入的数据量不大于PIPE_BUF时linux将保证写入的原子性。 当要写入的数据量大于PIPE_BUF时linux将不再保证写入的原子性。 3.管道的特点 1.只能用于具有共同祖先的进程具有亲缘关系的进程之间进行通信通常一个管道由一个进程创建然后该进程调用fork此后父、子进程之间就可应用该管道。 2.管道提供流式服务 3.一般而言进程退出管道释放所以管道的生命周期随进程 4.一般而言内核会对管道操作进行同步与互斥 5.管道是半双工的数据只能向一个方向流动需要双方通信时需要建立起两个管道 二、命名管道
1. 特点 1.管道应用的一个限制就是只能在具有共同祖先具有亲缘关系的进程间通信。 2.如果我们想在不相关的进程之间交换数据可以使用FIFO文件来做这项工作它经常被称为命名管道 3.命名管道是一种特殊类型的文件 2.创建命名管道
1.在命令行上 mkfifo 文件名2.在程序中
int mkfifo(const char *filename,mode_t mode);int main(int argc, char *argv[])
{mkfifo(p2, 0644);return 0;
}3.一个程序执行打开管道并不会真正打卡 我们执行这个程序发现并没有打印那句话说明管道文件并没有真正打开只有当我们执行另一个我们要通信的文件的时候管道才会真正打开
三、进程池简易实现
1.makefile
ProcessPool:ProcessPool.cppg -o $ $^ -stdc11 -g.PHONY:clean
clean:rm -rf ProcessPool2.Task.hpp #pragma once
#includefunctional#includevector#includeiostreamusing namespace std;void task1()
{std::cout lol 刷新日志 std::endl;
}
void task2()
{std::cout lol 更新野区刷新出来野怪 std::endl;
}
void task3()
{std::cout lol 检测软件是否更新,如果需要就提示用户 std::endl;
}
void task4()
{std::cout lol 用户释放技能更新用的血量和蓝量 std::endl;
}void LoadTask(vectorfunctionvoid()*tasks){
tasks-push_back(task1);
tasks-push_back(task2);
tasks-push_back(task3);
tasks-push_back(task4);
return ;
}3.ProcessPool.cpp 我们创建processnum个子进程让父进程来写子进程来读子进程读到任务号后进行对应的处理。 #include iostream
#include Task.hpp
#include assert.h
#include vector
#include string
#include unistd.h
#include sys/wait.h
#include sys/types.husing namespace std;
vectorfunctionvoid() tasks;
const int processnum 10;//创建的子进程数
class channel
{
public:channel( string processname, pid_t slaverid,int cmdcode): _processname(processname), _cmdfd(cmdcode), _slaverid(slaverid){}public:string _processname;//执行任务的进程名pid_t _slaverid;//执行任务的进程pidint _cmdfd;//朝几号管道去操作
};void Menu()
{std::cout ################################################ std::endl;std::cout # 1. 刷新日志 2. 刷新出来野怪 # std::endl;std::cout # 3. 检测软件是否更新 4. 更新用的血量和蓝量 # std::endl;std::cout # 0. 退出 # std::endl;std::cout ################################################# std::endl;
}void slaver()
{int cmdcode;while (true){int n read(0, cmdcode, sizeof(int));//读取任务码if (n sizeof(int)){cout slaver say get a command getpid() cmdcode: cmdcode endl;if (cmdcode 0 cmdcode tasks.size())tasks[cmdcode]();//执行任务}else if (n 0)//为0说明读到文件末尾之间breakbreak;}
}
void InitProcessPool(vectorchannel *channels)
{for (int i 0; i processnum; i){int pipefd[2] {0};int n pipe(pipefd);//使用两个文件描述符指向同一个管道文件assert(!n);pid_t id fork();if (id 0)//子进程{close(pipefd[1]);//关闭写文件dup2(pipefd[0], 0);//将读文件重定向到标准输入的位置close(pipefd[0]);//关闭当前读文件因为我们后续用标准输入的下标就行了slaver();//子进程读取任务码exit(0);}string name processname to_string(i);//子进程名字channels-push_back(channel(name, id, pipefd[1]));//子进程pid,这个子进程//与父进程之间的管道文件描述符下标记录下来// fatherclose(pipefd[0]);//关闭读文件}
}void ctrlProcess(vectorchannel channels)
{int which 0;
//我们循环调用各个子进程which为子进程的下标while (true){Menu();int select 0;cin select;cout Please Enter ;if (select 0 || select 5)break;int cmdcode select - 1;cout father say task have sent to channels[which]._processname cmdcode : cmdcode endl;write(channels[which]._cmdfd, cmdcode, sizeof(int));//写入指令which;which % channels.size();}
}void QuitProcess(const vectorchannel channels)
{//方法一for (const auto c : channels)close(c._cmdfd);for (const auto c : channels)waitpid(c._slaverid, nullptr, 0);//方法二//for(int ichannels.size()-1;i0;i--){// close(channels[i]._cmdfd);//waitpid(channels[i]._slaverid,nullptr,0);//阻塞等待//}
}int main()
{vectorchannel channels;//管理管道的数组LoadTask(tasks);//加载任务InitProcessPool(channels);//初始化进程池ctrlProcess(channels);//输入任务命令QuitProcess(channels);//中止进程return 0;
} 如果等待和close在一个循环中会发生阻塞因为我一号管道虽然父进程那里写关闭了但依旧有子进程23指向这个管道为写