3.进程
一.fork()
fork()用来创建一个子进程,子进程复制父进程的0-3G空间和父进程内核中的PCB,但子进程和父进程的id号不同。
fork()调用一次,返回两次
在父进程中返回子进程的PID,在子进程中返回0。
例:
#include <stdio.h> #include <unistd.h> #include <sys/types.h> int main() { pid_t pid; pid = fork(); if (pid > 0) { printf("cur process is parent\n"); printf("cur pid is: %d\n", getpid()); printf("cur parent pid is: %d\n", getppid()); while(1); } else if (pid == 0) { printf("cur process is child\n"); printf("cur pid is: %d\n", getpid()); printf("cur parent pid is: %d\n", getppid()); while(1); } else { perror("fork"); } return 0; }
运行结果:
cur process is parent
cur pid is: 5924
cur parent pid is: 2736
cur process is child
cur pid is: 5925
cur parent pid is: 5924
二.execl()&execv()&execle()&execve()&execlp()&execvp()
char *const ps_argv[] ={"ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL}; char *const ps_envp[] ={"PATH=/bin:/usr/bin", "TERM=console", NULL}; execl("/bin/ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL); execv("/bin/ps", ps_argv); execle("/bin/ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL, ps_envp); execve("/bin/ps", ps_argv, ps_envp); execlp("ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL); execvp("ps", ps_argv);
PS:
1.只有execve是真正的系统调用,其它五个函数最终都调用execve
2.由于exec函数只有错误返回值,只要返回了一定是出错了,所以不需要判断它的
返回值,直接在后面调用perror即可
例:
#include <unistd.h> #include <stdlib.h> int main() { // execl("/bin/ls", "ls", "-l", NULL); char *const ps_argv[] = {"ps", "aux", NULL}; //execvp("ps", ps_argv); execlp("ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL); perror("exec ps"); exit(1); return 0; }
运行结果:
PID PPID PGRP SESS TPGID COMMAND
2699 2693 2699 2699 3926 bash
3926 2699 3926 2699 3926 ps
三.wait()&waitpid()
◆ wait()
僵尸进程: 子进程退出,父进程没有回收子进程资源(PCB),则子进程变成僵尸进程(Z+)(当子进程运行结束后,其用户空间已被释放,但它的PCB没有被立即释放,等待父进程将其释放)
孤儿进程: 父进程先于子进程结束,则子进程成为孤儿进程,子进程的父进程成为1号进程init进程,称为init进程领养孤儿进程
可使用wait()函数除去僵尸进程
PS:
1.wait()函数是一个阻塞函数,等待回收子进程资源,如果没有子进程,wait返回-1
2.waitpid()函数则是一个非阻塞函数
#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/wait.h> int main() { pid_t pid; pid = fork(); if (pid > 0) { while (1) { printf("I am parent process\n"); printf("wait for child: %d\n", wait(NULL)); sleep(1); } } else if (pid ==0) { printf("I am child process\n"); printf("My pid is: %d\n", getpid()); sleep(10); } else { perror("fork"); } return 0; }
运行结果:
I am parent process
I am child process
My pid is: 5308
wait for child: 5308
I am parent process
wait for child: -1
I am parent process
wait for child: -1
I am parent process
wait for child: -1
I am parent process
wait for child: -1
I am parent process
wait for child: -1
I am parent process
wait for child: -1
◆ waitpid()
pid_t waitpid(pid_t pid, int *status, int options);
< -1 回收指定进程组内的任意子进程
-1 回收任意子进程
0 回收和当前调用waitpid一个组的所有子进程
> 0 回收指定ID的子进程
WNOHANG 如果没有子进程退出立即返回,这样就实现了非阻塞的wait
#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/wait.h> int main() { pid_t pid; pid = fork(); if (pid > 0) { while (1) { printf("I am parent process\n"); pid_t pid_c = waitpid(0, NULL, WNOHANG); printf("go to next...\n"); } } else if (pid == 0) { printf("I am child process\n"); sleep(10); } else { perror("fork"); } return 0; }
运行结果:
I am parent process
go to next...
I am parent process
go to next...
I am parent process
go to next...
I am parent process
go to next...
I am parent process
go to next...
I am parent process
go to next...
I am parent process
go to next...
I am parent process
go to next...