在PHP中Swoole的多进程之前写过很多,目前飞飞物联的一些高并发的API就建立再swoole之上,与PHP不同的是Linux下C语言的开多进程简单得多。
在c中多进程使用fork()函数,
直接看一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
#include <unistd.h> #include <stdio.h> int main () { pid_t fpid; //fpid表示fork函数返回的值 int count=0; fpid=fork(); if (fpid < 0) // 如果fork函数出错会返回0 printf("error in fork!"); else if (fpid == 0) { // fork返回0代表这是子进程 printf("i am the child process, my process id is %d\n",getpid()); count++; }else { // 父进程中,fork返回创建子进程的进程ID,由于这里不知道ID是多少 // 因此直接else一下这里就会是父进程了,因为绝对不会是0 printf("i am the parent process, my process id is %d\n",getpid()); count++; } printf("Count value is: %d/\n",count); return 0; } |
运行结果:
执行结果分析:
- 在执行fork之前只有一个进程执行代码,fork()被调用之后就会有两个进程执行这段相同的代码了
fork函数的特点是:
- 在父进程中,返回新创建的子进程ID
- 在子进程中,返回0
- 出现错误fork会返回一个负值,这就是为什么要先判断一下是不是负数。
上面的程序中就是用了fork返回值的这个特点来判断是子进程还是父进程。
执行顺序:
在创建了进程之后,系统中就出现了两个基本上完全相同的进程来执行之后的代码,这两个进程没有固定的先后顺序,哪个进程先执行要看系统进程的调度策略。
和swoole中的进程一样,每个进程都会有一个进程标识符通过getpid()获得,还有一个记录父进程pid的变量,通过getppid()获得
现在看这样一道题:
编写一个C程序,打开content.txt文件进行读取并调用fork()函数。 程序中的子进程将从文件中打印前150个字符,其余字符将由父进程打印。 但是,在输出中,我们应该看到字符的顺序与文件中可用的顺序相同。 除了在第150个字符后打印字符外,父进程还应在结尾处打印content.txt的新行数,字数和字节数。 使用已有的程序wc获取文件的行数,字数和字节数。 您必须使用exec()方法之一调用此程序。 查看wc手册以了解更多信息。 在终端中编译并执行程序。
先解决这样的问题:
- 调用fork()函数开两个进程
- 子进程打前150个字符
- 父进程打出后面的所有字符
在前面的示例中已经开了两个进程,但是这两个进程是没有先后顺序的,对应与swoole里面的异步任务,但是在这个问题中我们的输出是由顺序要求的,这是一个非常常见的需求。可以通过waitpid)函数来等待子进程终止,没有错误的情况下这个函数返回的值为正数或者wait()函数来实现。
继续用上一个例子的架子,使用wait()来阻塞父进程从而能够等待子进程执行完毕exit()之后再执行父进程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <sys/wait.h> #include <sys/types.h> int main () { pid_t fpid,pr; int count=0; fpid=fork(); if (fpid < 0) printf("fork error!"); else if (fpid == 0) { // child printf("child exit\n"); exit(0); } else { // father pr = wait(NULL); if(pr<0){ printf("Father process error"); } printf("i am father, i know child has exit"); } return 0; } |
多次执行这段程序:
可以看到,子进程执行完成之后才会执行父进程,然后我们就可以把读文件的流程添加上。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <sys/wait.h> #include <sys/types.h> int main () { pid_t fpid,pr; int count=0; fpid=fork(); if (fpid < 0) printf("fork error!"); else if (fpid == 0) { // child char c; freopen("content.txt","r",stdin); int count = 0; while(scanf("%c",&c)){ printf("%c",c); count++; if(count >= 150){ break; } } // printf("%d",count); // printf("child exit\n"); exit(0); } else { // father pr = wait(NULL); if(pr<0){ printf("Father process error"); } // printf("i am father, i know child has exit,i start to read"); char c; freopen("content.txt","r",stdin); int count = 0; while(scanf("%c",&c) != EOF){ count ++; if(count>150){ printf("%c",c); } } } return 0; } |
如果打开注释就可以很清楚的看到子进程打印了前150个,父进程打印了后面的内容:
接下来处理:
- 父进程还应在结尾处打印content.txt的行数
- 字符数
- 字节数。
- 使用exec()来
这里其实就是使用c语言执行shell的wc命令,man wc一下使用很简单
所以合在一起就是 wc -lwc filename
然后介绍一下exec(),这其实不是一个函数,是6个函数的总称,其实功能都一样只是参数不同看,因为C语言没有函数重载所以才有这么多个。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include <unistd.h> int execl(const char *path, const char *arg, ...); int execlp(const char *file, const char *arg, ...); int execle(const char *path, const char *arg, ..., char *const envp[]); int execv(const char *path, char *const argv[]); int execvp(const char *file, char *const argv[]); int execve(const char *path, char *const argv[], char *const envp[]); |
所以最后的代码就是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <sys/wait.h> #include <sys/types.h> int main () { pid_t fpid,pr; int count=0; fpid=fork(); if (fpid < 0) printf("fork error!"); else if (fpid == 0) { // child char c; freopen("content.txt","r",stdin); int count = 0; while(scanf("%c",&c)){ printf("%c",c); count++; if(count >= 150){ break; } } // printf("%d",count); // printf("child exit\n"); exit(0); } else { // father pr = wait(NULL); if(pr<0){ printf("Father process error"); } // printf("i am father, i know child has exit,i start to read"); char c; freopen("content.txt","r",stdin); int count = 0; while(scanf("%c",&c) != EOF){ count ++; if(count>150){ printf("%c",c); } } execlp("wc","wc","-lwc","./content.txt",NULL); } return 0; } |