全部代码:https://download.csdn.net/download/weixin_42295969/86504723
多进程的最经典的开发场景就是Nginx,这是因为多进程很适合做负载均衡,进程能够申请资源,而线程更多的则是资源共享。

分为前台和后台
运行效果如下:


在结构中对前台以及后台的划分:


在这里需要完成三个同步:1、开始进入消息队列发送接收之前的同步;2、对消息队列的发送与接收进行同步(这里系统调用的方法已经实现了同步);3、对消息队列接收之后的同步,这时候需要对命令处理之后信息进行输出,在后台处理,在前台输出;

因为之前想的是还要实现消息队列的同步,所以是想把发送以及接收放在同步之前,或者将接收的部分放在同步之后,其实这会导致下一个命令到来的问题,所以这才有图上的×,表示这个顺序是错误的。
但是由于消息队列已经是同步的了,所以只需要实现消息队列之前和之后的同步;
如何在消息队列前后实现同步以及同步的意义?
消息队列之前的同步:
通过建立有名管道实现同步,并管理内实现清零而已,保证之前是清零,因为这里实现了循环了,所以要保证每一个循环都是空的,然后再往里面写内容,同理消息队列之后的同步也是需要先做清零的
消息队列之后的同步:将结果输出,这里考虑到循环的问题,因为这也是共同的资源,所以也需要进行同步,所以同样通过有名管道将输出信息写进管道并进行读取;
在这里实现两大组合:fork+execl+waitpid和fork+prctl(PR_SET_PDEATHSIG, SIGKILL)
在waitpid的时候需要结合进程的三种状态进行判断:

进程的这三种状态也可以类比理发店排队的情景:

使用一个同步管道来维护前后台程序间的同步
writeSynPipe(); //写同步管道
sendMessage(msg, queId); //发送消息
readResPipe(); //读结果管道并打印
后台程序的同步代码为:
readSynPipe(); //读同步管道
if(readMessage(queId, &m) == -1) {
continue; //继续尝试
}
execCommand(m.text, resCommand); //执行命令
writeResPipe(resCommand); //将结果写入管道
其中synPipe是同步管道,resPipe是保存命令执行结果的管道。
与前台一样,首先通过消息队列进行同步,然后通过有名管道在消息队列前后进行同步
//核心代码
writePipe();
// 6.对消息队列发送消息,将转换后的指令发到消息队列中去
sendMessage(msg, queId);
// 7.读结果管道并进行打印
readPipe();//这里又重新创建管道了
convertCommand(pid, str, &msg);——前台将dir这样的windowns的指令转换linux下的指令ls
后台执行cmd指令并执行之后的结果void execCommand(const char *cmd, vector &res)
这里单独写了一个demo进行示例理解:
//执行shell指令,并将结果输出到字符串中
int myexec(const char *cmd, string &resvec)
{
resvec.clear();
FILE *pp = popen(cmd, "r"); //建立管道
if (!pp)
{
return -1;
}
char tmp[1024]; //设置一个合适的长度,以存储每一行输出
while (fgets(tmp, sizeof(tmp), pp) != NULL)
{
if (tmp[strlen(tmp) - 1] == '\n')
{
tmp[strlen(tmp) - 1] = '\0'; //去除换行符
}
resvec.append(tmp);
}
pclose(pp); //关闭管道
return resvec.size();
}
将ls进行执行,第一次结果

第二次结果:

可以看出pp就是命令行执行的结果,并能够通过一步步遍历获得输出结果
因为这里open里面的属性是r,表示对应到表述命令行里的标准输出,输入到返回的文件指针指向中去。以下是popen的详细理解说明
FILE * popen ( const char * command , const char * type );
int pclose ( FILE * stream );
#include
- 包含了一些基本的数据类型
key_t表示进程的关键字,能够区别同一程序的不同进程
#include- sys/ipc.h是一种通讯格式,可在2个(多数情况下)或多个进程间传递信息
- 匿名管道以及命名管道/消息队列都是需要这个头文件的
#include- 定义了消息队列相关
- 消息队列中发送以及接收消息
== #include== - 定义了使用wait相关的定义
- waitpid使指定进程堵塞
#include- 给进程或者线程重命名或者其他操作,基本的进程管理函数
- 实现在进程退出来的时候
- 我有一个分叉到子进程的进程。如果父进程存在,子进程不应该存在。所以,我在子进程中调用
:: prctl(PR_SET_PDEATHSIG,SIGKILL)来杀死父进程。最后发生的是父线程调用pthread_exit,并且该线程最终成为杀死子进程的催化剂。在父线程退出时调用prctl(PR_SET_PDEATHSIG,SIGNAL),而不是父进程退出
#include- 文件状态头文件还有一些常量
- mkfifo 创建一个名为 PATH 的新 FIFO,具有权限位 MODE
- umask(给文件管理权限赋予到最大值)
#include- cntl.h,是unix标准中通用的头文件,其中包含的相关函数有 open,fcntl,shutdown,unlink,fclose等!
- extern声明变量在其他地方,所以有时候比如unlink就在其他文件中,但是最终指向是
#include- unistd.h 中所定义的接口通常都是大量针对系统调用的封装(英语:wrapper functions),如 fork、pipe 以及各种 I/O 原语(read、write、close 等等)。
#include- errno.h 是C语言C标准函式库里的标头档,定义了通过错误码来回报错误资讯的宏。