父子进程
用系统调用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
| #include <stdio.h> #include <stdlib.h> #include <unistd.h>
int main() { printf("hello, world (pid: %d)\n", (int)getpid());
int rc = fork();
if (rc < 0) { fprintf(stderr, "fork failed\n"); exit(1); } else if (rc == 0) { printf("hello, I am the child (pid: %d)\n", (int)getpid()); } else { printf("hello, I am the parent of %d (pid: %d)\n", rc, (int)getpid()); }
return 0; }
|
wait 等待可以等待子进程完毕,避免子进程结束后资源无法收回成为僵尸进程。
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
| #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h>
int main() { printf("hello, world (pid: %d)\n", (int)getpid());
int rc = fork();
if (rc < 0) { fprintf(stderr, "fork failed\n"); exit(1); } else if (rc == 0) { printf("hello, I am the child (pid: %d)\n", (int)getpid()); } else { int status; wait(&status); printf("hello, I am the parent of %d (pid: %d)\n", rc, (int)getpid()); printf("%d",status); }
return 0; }
|
到现在可以明确一个道理,else 只是为了区分子进程和父进程谁先执行,但是子进程和父进程的代码块就是他们一定会执行的一些逻辑操作。你可以在不同代码块加上exit或者return 。把他当作一个程序去写。

编写一个程序,在调用fork()之前,让主进程访问一个变量(例如x),并将其值设置为某个值(例如100)。请问子进程中的变量是什么值?当子进程和父进程都改变x的值时,该变量会发生什么?
具体来说,fork()
会创建一个子进程,但在最开始,父进程和子进程的内存内容是相同的,并不是完全独立的。它们共享同一块内存区域,直到其中一个进程修改了某个变量(比如 x
),操作系统才会为修改该变量的进程分配一块新的内存副本。
关键点:
- 初始共享:
fork()
后,父子进程在内存中是共享的,直到其中一个进程进行写操作。父子进程并不会立刻各自拥有独立的内存副本。
- 写时复制(COW):当父进程或子进程修改某个共享的内存区域时,操作系统会为该进程创建一个独立的副本(这就是写时复制),确保两个进程不互相影响。
举个例子:
- 假设在
fork()
之后,父进程和子进程都访问变量 x
,初始时它们的 x
值相同。
- 只有当父进程或子进程修改
x
时,操作系统才会为修改 x
的进程分配新的内存副本。
所以,尽管在 fork()
之后父子进程的内存空间是独立的,实际操作中,它们初始时通过写时复制共享了内存,直到其中一个进程做出修改。
wait 前面的逻辑
如果在父进程调用 wait()
函数之前还有其他的逻辑,父进程会执行这些逻辑,并 不会立即 等待子进程。
wait()
函数的作用是使父进程等待其子进程的结束,直到子进程退出并收集到它的退出状态。如果在调用 wait()
之前执行了其他操作,父进程在这些操作完成后才会进入等待状态。所以,如果在 wait()
之前有逻辑执行,那么父进程会先执行这些逻辑,直到程序执行到 wait()
,才会开始等待子进程的结束。我好像突然懂了。一般来讲子进程和父进程并发执行,但是如果说子进程先执行,其实父进程wait函数就没作用,但是父进程先执行,执行到wait会自动等待
执行命令
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
| #include <stdio.h> #include <stdlib.h> #include <sys/wait.h> #include <fcntl.h> #include <unistd.h> #include <string.h>
int main() { printf("hello, world (pid: %d)\n", (int)getpid()); int rc = fork(); if (rc < 0) { fprintf(stderr, "fork failed\n"); exit(1); } else if (rc == 0) { char *args[] = { "ps", "aux", NULL }; execvp(args[0], args); printf("hello, I am the child (pid: %d)\n", (int)getpid()); return 1; } else { int status; wait(&status); printf("hello, I am the parent of %d (pid: %d)\n", rc, (int)getpid()); printf("%d\n",status);
}
return 0; }
|