博客文章

进程控制fork

作者: andy.      时间: 2016-08-17 10:36:41

简单介绍以下fork得用法。标准库中有个system可以直接执行系统命令。fork创建一个新的进程,接着两个进程从fork位置开始往下执行,两个进程共享同一个文件描述符等等,如果想要关闭该文件的话,需要同时关闭。execve就是执行另外一个程序了,然后替换掉当前进程。

fork在调用后,成功了的话就存在两个进程了,两个进程在代码fork位置都会返回,其中原进程返回子进程的pid,子进程返回0。失败的话,原进程返回其他。好了,来看一个例子:

#include
<stdio.h>
#include
<sys/types.h>
#include
<unistd.h>
 
int main(){
        pid_t pid = fork();
 
        if(pid == 0){
                printf("This message from
new.\t");
                printf("My PID is:
%d\t", getpid());
                printf("My ppid is:
%d\n", getppid());
        }else{
                printf("This message from
old.\t");
                printf("This new proccess'
PID is: %d\t", pid);
                printf("My PID is:
%d\n", getpid());
        }
}
This message from old.  This new proccess' PID is: 1287 My PID is: 1286
This message from new.  My PID is: 1287 My ppid is: 1
[[email protected] proccess]# ./a.out 
This message from old.  This new proccess' PID is: 1289 My PID is: 1288
This message from new.  My PID is: 1289 My ppid is: 1288
[[email protected] proccess]# ./a.out 
This message from old.  This new proccess' PID is: 1291 My PID is: 1290
This message from new.  My PID is: 1291 My ppid is: 1290
[[email protected] proccess]# ./a.out 
This message from old.  This new proccess' PID is: 1293 My PID is: 1292
This message from new.  My PID is: 1293 My ppid is: 1

左边是代码,右边是运行结果。可以看出fork出来的进程是原进程的子进程。等等,为什么有时候子进程读取父进程的时候会返回1呢~可以参考这个:Why getppid() from the child return 1,stackoverflow的一个提问。在子进程调用getppid的时候,父进程进程已经退出了,变成了孤儿进程,那么就会返回1。

说到孤儿进程,那么就有僵死进程。在运行过程中,父进程没有调用wait,子进程已经退出了,但是进程号依旧占用着,那么就回产生僵死进程。看代码:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main(){
        pid_t pid = fork();

        if(pid == 0){
                printf("This message from new.\t");
                printf("My PID is: %d\t", getpid());
                printf("My ppid is: %d\n", getppid());
        }else if(pid != -1){
                sleep(60);
                printf("This message from old.\t");
                printf("This new proccess' PID is: %d\t", pid);
                printf("My PID is: %d\n", getpid());
        }
}

子进程立马退出,但是父进程没有调用wait。运行后输出结果:

[[email protected] proccess]# ./a.out
This message from new.  My PID is: 1368 My ppid is: 1367

开启新的终端后,ps查看进程:

root      1336  0.4  0.3   6300  3952 pts/1    Ss   23:07   0:00 -bash
root      1367  0.0  0.0   2156   568 pts/0    S+   23:07   0:00 ./a.out
root      1368  0.0  0.0      0     0 pts/0    Z+   23:07   0:00 [a.out] <defunct>
root      1371  0.0  0.3   8336  3744 pts/1    R+   23:07   0:00 ps -aux

“defunct”,死掉掉的进程。但是它依旧占用着进程号,其他资源已经释放掉了。

wait操作避免僵死进程,看代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

int main(){
        pid_t pid = fork();
        int status;

        if(pid == 0){
                return 23;
        }else if(pid != -1){
                wait(&status);
                printf("Child's returned value:%d\n", WEXITSTATUS(status));
                sleep(60);
        }
}

wait 还可以获取子进程的返回值。运行结果就不看了,看这边的ps结果吧:

root      1487  0.0  0.0      0     0 ?        S    23:16   0:00 [kworker/1:1]
root      1505  0.0  0.0   2160   580 pts/0    S+   23:17   0:00 ./a.out
root      1507  0.0  0.3   8336  3688 pts/1    R+   23:17   0:00 ps -aux

其实上面的return 可以使用exit函数来代替,是完全没有问题的。毕竟都是正常退出。


看看execve,代码:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main(){
    char * args[]={"/bin/ls", "-l", NULL};
        //类似与main 第一个参数是路径
        execve("/bin/ls", args, NULL);
        //进程被替换 但是打开的文件描述符同样有效
        printf("hello, world");
}

运行结果:

[[email protected] proccess]# ./a.out 
total 40
-rw-r--r--. 1 root root  352 Aug 15 05:09 1.c
-rw-r--r--. 1 root root  387 Aug 15 08:26 2.c
-rw-r--r--. 1 root root  175 Aug 15 10:30 3.c
-rw-r--r--. 1 root root  280 Aug 16 23:17 4.c
-rw-r--r--. 1 root root   32 Aug 16 23:22 5.c
-rwxr-xr-x. 1 root root 7304 Aug 16 23:23 5.out
-rw-r--r--. 1 root root  281 Aug 16 23:24 6.c
-rwxr-xr-x. 1 root root 7380 Aug 16 23:25 a.out

我们可以看到调用execve后,后面的代码都是没有执行的。




第一段代码的排版好像有问题,不过将就以下好了~

以后的文章中尽量不会出现图片,体验太差了。