Linux下的进程通信:匿名管道(模拟实现一个父进程与多个子进程间的通信)

1.进程间通信的目的

a.数据传输

b.资源共享

c.消息通知

d.进程控制


2.匿名管道的实现原理

我们都知道进程是存在内存中的,那么我们要实现进程通信的前提是必须在内存中找到一块共享区域。这块区域不属于父子进程中的任意一个。这片公共区域就可以称之为父子进程通信的管道。

 管道就和文件的使用方法差不多,我们只需要留下需要对它操作部分的权限。这样就可以实现父进程发送数据到管道,子进程从管道读出数据。

但是,要注意匿名管道这种通信是半双工的,只能从一边传入另一边,不可以俩边一起读或者一起写。


3.pipe函数

int arr[2]={0};
int ret=pipe(arr);

这个函数可以用来开辟一个管道。我们只需要传入一个大小为2的数组进去,返回值为0表示创建成功。arr[0]就是代表以read的方式打开管道的文件描述符fd,arr[1]就是表示以write的方式打开管道的文件描述符fd。


4.来实现一个简单的单父进程与多个子进程间的通信

a.task.h文件

#pragma once2 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 10 using namespace std;11 12 typedef function func; //打包下面的任务13 vector callbacks; 14 unordered_map mp; //用下标与任务对应起来15 16 void readWysql()17 {18   cout<<"sub process ["<

b. test.cpp文件

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "Task.hpp"#define PROCESS_NUM 5using 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 << "main process: call process " << who << " execute " << desc[command] << " through " << fd << endl;
}int main()
{// 代码中关于fd的处理,有一个小问题,不影响我们使用,但是你能找到吗??load();// pid: pipefdvector> 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]);// childwhile (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]); // pipefd[1]slots.push_back(pair(id, pipefd[1]));}// 父进程派发任务srand((unsigned long)time(nullptr) ^ getpid() ^ 23323123123L); // 让数据源更随机while (true){// 选择一个任务, 如果任务是从网络里面来的?int command = rand() %  handlerSize();// 选择一个进程 ,采用随机数的方式,选择进程来完成任务,随机数方式的负载均衡int choice = rand() % slots.size();// 把任务给指定的进程sendAndWakeup(slots[choice].first, slots[choice].second, command);sleep(1);//手输入任务的方式(菜单)// int select;// int command;// cout << "############################################" << endl;// cout << "#   1. show funcitons      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);// }// else// {// }}// 关闭fd, 所有的子进程都会退出for (const auto &slot : slots){close(slot.second);}// 回收所有的子进程信息for (const auto &slot : slots){waitpid(slot.first, nullptr, 0);}
}

最后来看看结果吧(采用的是随机数的方式)

 


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部