第八夜:进程、多进程

进程

Linux下C语言进程相关的函数主要有:

函数 说明
getpid() 获取当前进程ID
getppid() 获取父进程ID
getpgrp() 获取进程组ID
fork() 创建子进程
wait() 等待子进程结束

fork()函数是Linux系统下C语言用来创建子进程的函数。最简单的用法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>
#include <unistd.h>

int main(void){
pid_t pid;

pid=fork();
printf("%d->%d\n",getpid(),pid);

}

/*
执行结果:
14929->14930
14930->0
*/

可以看到,fork()函数后的printf函数,执行了两次,一次是在进程ID为14920的进程中,打印pid的值为14930。另一次是在进程ID为14930的进程中,打印了0。
这就是fork()函数的用法,它会在程序中返回两次,在父进程中的返回值是子进程的进程ID,子进程中返回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
50
51
52
53
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>

int glob = 1;

int main(void){
int var = 2;

pid_t pid;

printf("ProcessID(%d) ParentProcessID(%d)\n", getpid(),getppid());
printf("&var: %x\t&glob: %x\tvar(%d)\tglob(%d)\n", &var,&glob, glob, var);


if ((pid = fork()) < 0) {
// 进程创建失败
printf("Fock Error");
} else if (pid == 0) {
//位于子进程中
printf("\n");
printf("ProcessID(%d) ParentProcessID(%d)\n", getpid(),getppid());
sleep(2);
glob++;
var++;
printf("ProcessID(%d) ParentProcessID(%d)\n", getpid(),getppid());
printf("&var: %x\t&glob: %x\tvar(%d)\tglob(%d)\n", &var,&glob, glob, var);
printf("\n");
} else {
// 位于父进程中
sleep(1);
//wait(&pid);
printf("&var: %x\t&glob: %x\tvar(%d)\tglob(%d)\n", &var,&glob, glob, var);
}

}

/*
执行结果:
[email protected]:~$gcc -m32 -o test test.c && ./test
ProcessID(14581) ParentProcessID(3595)
&var: ff92f988 &glob: 56638030 var(1) glob(2)

ProcessID(14582) ParentProcessID(14581) // 父进程执行时,两个进程是父子关系。
&var: ff92f988 &glob: 56638030 var(1) glob(2)
[email protected]:~$ProcessID(14582) ParentProcessID(1099) //父进程退出后,子进程交由系统接管。
&var: ff92f988 &glob: 56638030 var(2) glob(3)


[email protected]:~$

*/

在此例中,程序是以双进程的方式在系统中执行的。并且父进程比子进程执行时间短,所以父进程先结束,子进程在父进程退出后,仍然在控制台打印出信息,是因为在父进程退出后,子进程会交由系统接管,此时子进程的父进程ID变成了一个系统进程(systemd或者init)。

多进程

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
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>

int main(void){
int i=0;
for(i=0;i<3;i++){
pid_t fpid = fork();
if(fpid==0)
printf("\tSon: %d (%d)\n",getpid(),getppid());
else
wait(0);
printf("Father: %d (%d)\n",getpid(),getppid());
}
return 0;
}

/*
执行结果:
Son: 16013 (16012)
Father: 16013 (16012)
Son: 16014 (16013)
Father: 16014 (16013)
Son: 16015 (16014)
Father: 16015 (16014)
Father: 16014 (16013)
Father: 16013 (16012)
Son: 16016 (16013)
Father: 16016 (16013)
Father: 16013 (16012)
Father: 16012 (3595)
Son: 16017 (16012)
Father: 16017 (16012)
Son: 16018 (16017)
Father: 16018 (16017)
Father: 16017 (16012)
Father: 16012 (3595)
Son: 16019 (16012)
Father: 16019 (16012)
Father: 16012 (3595)
*/

一个完整的多进程示例:

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
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>

int sub_func(int sec){
printf("\tProcess:%d, ParentProcess(%d), sec(%d)\n",getpid(),getppid(),sec);
sleep(sec);
return 0;
}

int main(void){
int i=0;
printf("Father: %d (%d)\n",getpid(),getppid());

for(i=0;i<3;i++){
pid_t fpid = fork();
if(fpid==0){
sub_func(i);
}else{
wait(&fpid);
}
}
return 0;
}

/*
编译:gcc -m32 -o test test.c && ./test
执行结果:
Father: 18081 (3595)
Process:18082, ParentProcess(18081), sec(0)
Process:18083, ParentProcess(18082), sec(1)
Process:18084, ParentProcess(18083), sec(2)
Process:18088, ParentProcess(18082), sec(2)
Process:18089, ParentProcess(18081), sec(1)
Process:18090, ParentProcess(18089), sec(2)
Process:18091, ParentProcess(18081), sec(2)
*/

第九夜:C语言常见的Linux系统调用 第七夜:线程、多线程
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×