进程:占用内存空间的正在运行的程序
PID:进程ID, linux下用ps au
查看
fork 函数
//成功时返回进程ID,失败返回-1
pid_t fork(void);
当前运行的进程调用fork(),复制正在运行的,调用fork函数的进程,内存相同的内存空间也被复制,包括各种变量值,但是,调用fork之后的程序流要根据fork函数的返回值加以区分。
- 父进程:fork函数返回子进程ID
- 子进程:fork函数返回0
示例程序
int gval = 10;
int main(int argc, char *argv[]) {
pid_t pid;
int lval = 20;
gval++; //11
lval += 5; //25
pid = fork(); //调用后程序已经复制了一份,创建了子进程
// 注意:fork函数会返回两次,一次是父进程返回,一次是子进程返回
// 父进程:返回值是子进程ID
// 子进程:返回值是 0
if (pid == 0) { //子进程
gval += 2; //13
lval += 2; //27
} else { //父进程
gval -= 2; //9
lval -= 2; //23
}
if (pid == 0) {
printf("child proc: [%d %d] \n", gval, lval);
} else {
printf("pid: %d, Parent proc: [%d %d] \n", pid, gval, lval);
}
return 0;
}
结果如下:
僵尸进程
产生原因
调用fork函数产生的子进程的终止方式
- 传递参数并调用exit函数
- main函数中执行return语句并返回值
向exit传递的参数值和main函数return返回值最终都会传递给操作系统,但操作系统不会销毁子进程,直到把这些值传递给产生该子进程的父进程。处在这种状态下的进程就是僵尸进程。
僵尸进程何时销毁?
向创建子进程的父进程传递子进程的exit参数值或return语句的返回值
如何传递这些值?
操作系统不会主动传递,只有父进程主动发起请求(函数调用)时,操作系统才会传递该值。
销毁僵尸进程
wait函数
调用wait函数,调用此函数时如果已有子进程终止,那么子进程终止时传递的返回值将保存在该函数参数所指内存空间。
#include <sys/wait.h>
// 成功时返回终止的子进程的pid,失败时返回-1
pit_t wait(int *statloc);
- WIFEEXITED:子进程正常终止时返回true
- WEXITSTATUS:返回子进程的返回值 调用代码如下:
if(WIFEEXITED(status)) {
puts("正常终止");
printf("child pass num :%d", WEXITSTATUS(status));
}
注意:调用wait
时,如果没有已终止的子进程,那么程序将阻塞,直到有子进程终止。
完整代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, char *argv[]) {
int status;
pid_t pid = fork();
if (pid == 0) {
return 3;
} else {
printf("child pid : %d \n", pid);
pid = fork();
if (pid == 0) {
exit(7);
} else {
printf("child pid : %d \n", pid);
wait(&status);
if (WIFEXITED(status)) {
printf("child send one: %d \n", WEXITSTATUS(status));
}
wait(&status);
if (WIFEXITED(status)) {
printf("child send two: %d \n", WEXITSTATUS(status));
}
sleep(30);
}
}
return 0;
}
waitpid 函数
可以防止阻塞
// 成功时返回终止的子进程的ID,失败返回-1
pid_t waitpid(pid_t pid, int *statloc, int options);
pid: 等待终止的子进程的ID,若传递-1,可以等待任意子进程终止
statloc:同wait函数的statloc
options:一般传递 WHOHANG
int main(int argc, char *argv[]) {
int staus;
pid_t pid = fork();
if (pid == 0) {
sleep(15);
return 24;
} else {
while (!waitpid(-1, &staus, WNOHANG)) {
sleep(3);
puts("sleep 3sec");
}
if (WIFEXITED(staus)) {
printf("child send %d \n", WEXITSTATUS(staus));
}
}
return 0;
}
➜ hello_server gcc waitpid.c -o waitpid
➜ hello_server ./waitpid
sleep 3sec
sleep 3sec
sleep 3sec
sleep 3sec
sleep 3sec
child send 24