fork
fork 函數創建子進程成功後,父進程返回子進程的 pid,子進程返回0。具體描述如下:
- fork返回值為-1, 代表創建子進程失敗
- fork返回值為0,代表子進程創建成功,這個分支是子進程的運行邏輯
- fork返回值大於0,這個分支是父進程的運行邏輯,並且返回值等於子進程的 pid
我們看下通過 fork 系統調用來創建子進程的例子:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t pid = fork();
if(pid == -1){
printf("create child process failed!n");
return -1;
}else if(pid == 0){
printf("This is child process!n");
}else{
printf("This is parent process!n");
printf("parent process pid = %dn",getpid());
printf("child process pid = %dn",pid);
}
getchar();
return 0;
}
運行結果:
$ ./a.out
This is parent process!
parent process pid = 25483
child process pid = 25484
This is child process!
從上面的運行結果來看,子進程的pid=25484, 父進程的pid=25483。
在前面介紹內存缺頁異常的時候,提到寫時複製 COW 是一種推遲或者避免複製數據的技術,主要用在 fork 系統調用里,當執行 fork 創建新子進程時,內核不需要複製父進程的整個進程地址空間給子進程,而是讓父進程和子進程共享同一個副本,只有寫入時,數據才會被複制。我們用一個簡單里的例子描述下:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int peter = 10;
int main()
{
pid_t pid = fork();
if(pid == -1){
printf("create child process failed!n");
return -1;
}else if(pid == 0){
printf("This is child process, peter = %d!n", peter);
peter = 100;
printf("After child process modify peter = %dn", peter);
}else{
printf("This is parent process = %d!n", peter);
}
getchar();
return 0;
}
執行結果:
$ ./a.out
This is parent process = 10!
This is child process, peter = 10!
After child process modify peter = 100
從運行結果可以看到,不論子進程如何去修改 peter 的值,父進程永遠看到的是自己的那一份。

vfork
接下來看下使用 vfork 來創建子進程:
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int peter = 10;
int main()
{
pid_t pid = vfork();
if(pid == -1){
printf("create child process failed!n");
return -1;
}else if(pid == 0){
printf("This is child process, peter = %d!n", peter);
peter = 100;
printf("After child process modify peter = %dn", peter);
exit(0);
}else{
printf("This is parent process = %d!n", peter);
}
getchar();
return 0;
}
運行結果:
$ ./a.out
This is child process, peter = 10!
After child process modify peter = 100
This is parent process = 100!
從運行結果中可以看出,當子進程修改了 peter=100 之後,父進程中打印 peter 的值也是100。

C/C++Linux服務器開發/後台架構師【零聲教育】-學習視頻教程-騰訊課堂
【文章福利】:小編整理了一些個人覺得比較好的學習書籍、視頻資料共享在群文件裡面,有需要的可以自行添加哦!~點擊加入(832218493需要自取)

pthread_create
現在我們知道了創建進程有兩種方式:fork,vfork。那麼創建線程呢?
線程的創建接口是用 pthread_create:
#include <pthread.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/syscall.h>
int peter = 10;
static pid_t gettid(void)
{
return syscall(SYS_gettid);
}
static void* thread_call(void* arg)
{
peter = 100;
printf("create thread success!n");
printf("thread_call pid = %d, tid = %d, peter = %dn", getpid(), gettid(), peter);
return NULL;
}
int main()
{
int ret;
pthread_t thread;
ret = pthread_create(&thread, NULL, thread_call, NULL);
if(ret == -1)
printf("create thread faild!n");
ret = pthread_join(thread, NULL);
if(ret == -1)
printf("pthread join failed!n");
printf("process pid = %d, tid = %d, peter = %dn", getpid(), gettid(), peter);
return ret;
}
運行結果:
$ ./a.out
create thread success!
thread_call pid = 9719, tid = 9720, peter = 100
process pid = 9719, tid = 9719, peter = 100
從上面的結果可以看出:進程和線程的 pid 都是相同的。當線程修改了 peter = 100 之後,父進程中打印 peter 的值也是100。

進程線程創建總圖
上面介紹了用戶態創建進程和線程的方式,以及各個方式的特點。關於其底層的實現本質,我們後面會詳細講解。這裡先提供一下三者之間的關係,可見三者最終都會調用 do_fork 實現。

但是內核態沒有進程線程的概念,內核中只認 task_struct 結構,只要是 task_struct 結構就可以參與調度。
原創文章,作者:投稿專員,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/230991.html
微信掃一掃
支付寶掃一掃