fork和僵屍進程
1. 關於fork
fork()函數:
用於創建一個進程,所創建的進程復制父進程的代碼段/數據段/BSS段/堆/棧等所有用戶空間信息;在內核中操作系統重新為其申請了一個PCB,並使用父進程的PCB進行初始化;
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
|
#include <iostream>
#include <unistd.h>
using
namespace
std;
int
val = 10;
int
main(
int
argc,
char
*argv[])
{
pid_t pid;
int
lval = 20;
pid = fork();
if
(pid == 0){
val += 2;
lval += 5;
}
else
{
val -= 2;
lval += 5;
}
if
(pid == 0){
cout <<
"val:"
<< val <<
", lval = "
<< lval << endl;
}
else
{
cout <<
"val:"
<< val <<
", lval = "
<< lval << endl;
}
return
0;
}
|
對於父進程而言,fork()函數返回子進程的ID(子進程的PID);而對於子進程而言,fork函數返回0。
僵屍進程
父進程創建子進程后,子進程運行到終止時刻(例如,調用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
int
main(){
pid_t pid = fork();
if
(pid == 0){
cout <<
"I am a Child Process."
<<endl;
}
else
{
cout <<
"I am a Father Process and Child Process is "
<< pid << endl;
sleep(30);
//讓父進程休眠30秒,此時便於觀察子進程的狀態
}
if
(pid == 0){
cout <<
" Child Process exits "
<< endl;
}
else
{
cout <<
"Father Process exits "
<< endl;
}
return
0;
}
|
此時,運行該程序,查看后台進程可知(test16是該測試程序的名稱,defunct表示僵屍進程):
gqx@gqx-Lenovo-Product:~$ ps -au USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 923 0.6 0.9 480840 159824 tty7 Ssl+ 4月09 36:07 /usr/lib/xorg/ root 1351 0.0 0.0 17676 1768 tty1 Ss+ 4月09 0:00 /sbin/agetty - ... gqx 24856 0.0 0.0 0 0 pts/11 Z+ 11:03 0:00 [tes16] <defunct> gqx 24859 0.0 0.0 39104 3300 pts/3 R+ 11:03 0:00 ps -au
僵屍進程的消除
方法一:調用wait()
函數:
/* Wait for a child to die. When one does, put its status in *STAT_LOC and return its process ID. For errors, return (pid_t) -1. This function is a cancellation point and therefore not marked with __THROW. */ extern __pid_t wait (__WAIT_STATUS __stat_loc);
成功返回終止的進程ID,失敗返回-1;子進程的最終返回值將指向該函數參數所指向的內存空間,但函數所指向的內存單元總還含有其他的信息,需要使用宏進行分離。
# define WIFEXITED(status) __WIFEXITED (__WAIT_INT (status)) //子進程正常終止返回"true" # define WEXITSTATUS(status) __WEXITSTATUS (__WAIT_INT (status)) //返回子進程的返回值
要注意的是:如果沒有已終止的子進程,那么程序將被阻塞,直到有子進程終止。
方法二:調用waitpid()
函數
/* Wait for a child matching PID to die. If PID is greater than 0, match any process whose process ID is PID. If PID is (pid_t) -1, match any process. If PID is (pid_t) 0, match any process with the same process group as the current process. If PID is less than -1, match any process whose process group is the absolute value of PID. If the WNOHANG bit is set in OPTIONS, and that child is not already dead, return (pid_t) 0. If successful, return PID and store the dead child's status in STAT_LOC. Return (pid_t) -1 for errors. If the WUNTRACED bit is set in OPTIONS, return status for stopped children; otherwise don't. This function is a cancellation point and therefore not marked with __THROW. */ extern __pid_t waitpid (__pid_t __pid, int *__stat_loc, int __options);
第一個參數:如果__pid
的值是-1,則與wait()
函數相同,可以等待任意的子程序終止;如果是0,則等待進程組識別碼與目前進程相同的任何子進程;如果pid>0,則等待任何子進程識別碼為 pid 的子進程。
第二個參數:與前一個函數wait()
的參數意義相同。
第三個參數:常用WNOHANG——若pid指定的子進程沒有結束,則waitpid()函數返回0,不予以等待。若結束,則返回該子進程的ID。
示例程序如下:
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
|
#include <iostream>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
using
namespace
std;
void
read_childproc(
int
sig){
int
status;
pid_t id = waitpid(-1, &status, WNOHANG);
if
(WIFEXITED(status)){
printf
(
"Remove proc id: %d \n"
, id);
printf
(
"Child send: %d \n"
, WEXITSTATUS(status));
}
}
int
main(){
pid_t pid;
struct
sigaction act;
act.sa_handler = read_childproc;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGCHLD, &act, 0);
pid = fork();
if
(pid == 0){
puts
(
"Hi, I am a child process!"
);
sleep(6);
return
12;
}
else
{
printf
(
"Child proc id: %d \n"
, pid);
pid = fork();
if
(pid == 0){
puts
(
"Hi, I am a child process!"
);
sleep(13);
exit
(24);
}
else
{
int
i;
printf
(
"Child proc id: %d \n"
, pid);
for
(i = 0; i < 4; i++){
puts
(
"wait..."
);
sleep(5);
}
}
}
return
0;
}
|