书接上文,倘若我们需要对多个子进程进行通信,该怎么做呢?简而言之,只需要我们保存下每个匿名管道的读端,或是写端即可。此方法只可以对有亲缘关系的进程才有作用
demo代码如下:
#include<iostream>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<cstdio>
#include<vector>
#include<cstdlib>
#include<unordered_map>
using namespace std;
typedef void(*func)();
vector<func>functors;
unordered_map<uint32_t,string>info;
typedef pair<int64_t,int64_t>elem;
vector<elem>callmap;
int processnum=5;
void f1(){cout<<"this is a log.txt id:"<<getpid()<<" time is"<<time(nullptr)<<endl;}
void f2(){cout<<"this is a copy.txt id:"<<getpid()<<" time is"<<time(nullptr)<<endl;}
void f3(){cout<<"this is a network.txt id:"<<getpid()<<" time is"<<time(nullptr)<<endl;}
void loadfunctor()
{
info.insert(make_pair<uint32_t,string>(functors.size(),"deal log.txt"));
functors.push_back(f1);
info.insert(make_pair<uint32_t,string>(functors.size(),"deal copy.txt"));
functors.push_back(f2);
info.insert(make_pair<uint32_t,string>(functors.size(),"deal network.txt"));
functors.push_back(f3);
}
void work(int fd)
{
while(true)
{
uint32_t num=0;
ssize_t s=read(fd,&num,sizeof(uint32_t));
if(s==0) break;
if(num<functors.size()) functors[num%functors.size()]();
}
cout<<getpid()<<"结束工作"<<endl;
}
void sendtask(vector<elem> &mp)
{
//srand((long long)time(nullptr));
int cnt=20;
while(cnt--)
{
cout<<cnt<<endl;
uint32_t pick=rand()%mp.size();
uint32_t task=rand()%functors.size();
cout<<"pick:"<<pick<<"task"<<task<<endl;
write(mp[pick].second,&task,sizeof(task));
cout<<"指派任务:"<<info[task]<<"给"<<mp[pick].first<<endl;
sleep(1);
}
for(int i=0;i<processnum;i++)
{
close(mp[i].second);
}
}
void dispatch(int num,int* task)
{
write(callmap[num].second,task,sizeof(*task));
}
int main()
{
loadfunctor();
for(int i=0;i<processnum;i++)
{
int pipefd[2];
pipe(pipefd);
pid_t id=fork();
if(id==0)
{
close(pipefd[1]);
work(pipefd[0]);
exit(0);
}
close(pipefd[0]);
elem m(id,pipefd[1]);
callmap.push_back(m);
}
sendtask(callmap);
for(int i=0;i<processnum;i++)
{
if(waitpid(callmap[i].first,nullptr,0)) cout<<"wait success:"<<callmap[i].first<<" number:"<<i<<endl;
close(callmap[i].second);
}
}
我们的父进程保存了每个子进程记录的管道的写端,并把子进程的pid号和匿名管道的写端做成一个键值对,至此,我们的父进程就可以操控多个子进程了。
非亲缘进程的通信
上述的方法可以实现有亲缘关系的进程进行通信,但是如果非亲缘关系的进程该如何通过管道进行通信呢?这里我们可以使用命名管道。
通过命名管道,我们可以实现非亲缘的进程进行通信,该方法是面向字节流的,先进先出。
demo代码如下:
//common.h
#pragma once
#include<iostream>
#include<string>
#define IPC_PATH ("./.fifo")
//client.cc
#include<iostream>
#include<sys/types.h>
#include<sys/stat.h>
#include"common.h"
#include<fcntl.h>
#include<string>
#include<unistd.h>
using namespace std;
int main()
{
int pipefd=open(IPC_PATH,O_RDONLY);
char buffer[1024];
while(true)
{
ssize_t s=read(pipefd,buffer,sizeof(buffer)-1);
if(s==0)break;
buffer[s]='\0';
printf("a msg from server:%s",buffer);
}
return 0;
}
//server.cc
#include<iostream>
#include<sys/types.h>
#include<sys/stat.h>
#include"common.h"
#include<fcntl.h>
#include<string>
#include<unistd.h>
#include<cstring>
#include<stdio.h>
using namespace std;
int main()
{
umask(0);
if(mkfifo(IPC_PATH,0600)!=0)
{
cerr<<"mkfifo error"<<endl;
//return 1;
}
int pipefd=open(IPC_PATH,O_WRONLY);
char str[1024];
while(true)
{
cout<<"please enter in:";
fgets(str,sizeof(str),stdin);
if(str=="###"){
close(pipefd);
break;
}
write(pipefd,&str,sizeof(str));
}
cout<<"hello client"<<endl;
}