使用者態程序執行緒的建立 forkvforkpthread_create

fork

fork 函式建立子程序成功後,父程序返回子程序的 pid,子程序返回0。具體描述如下:

fork返回值為-1, 代表建立子程序失敗

fork返回值為0,代表子程序建立成功,這個分支是子程序的執行邏輯

fork返回值大於0,這個分支是父程序的執行邏輯,並且返回值等於子程序的 pid

我們看下透過 fork 系統呼叫來建立子程序的例子:

#include #include #include 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 = %d\n”,getpid()); printf(“child process pid = %d\n”,pid); } getchar(); return 0;}

執行結果:

$ 。/a。outThis is parent process!parent process pid = 25483child process pid = 25484This is child process!

從上面的執行結果來看,子程序的pid=25484, 父程序的pid=25483。

在前面介紹記憶體缺頁異常的時候,提到寫時複製 COW 是一種推遲或者避免複製資料的技術,主要用在 fork 系統呼叫裡,當執行 fork 建立新子程序時,核心不需要複製父程序的整個程序地址空間給子程序,而是讓父程序和子程序共享同一個副本,只有寫入時,資料才會被複制。我們用一個簡單裡的例子描述下:

#include #include #include 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 = %d\n”, peter); }else{ printf(“This is parent process = %d!\n”, peter); } getchar(); return 0;}

執行結果:

$ 。/a。outThis is parent process = 10!This is child process, peter = 10!After child process modify peter = 100

從執行結果可以看到,不論子程序如何去修改 peter 的值,父程序永遠看到的是自己的那一份。

使用者態程序/執行緒的建立 fork/vfork/pthread_create

vfork

接下來看下使用 vfork 來建立子程序:

#include #include #include #include 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 = %d\n”, peter); exit(0); }else{ printf(“This is parent process = %d!\n”, peter); } getchar(); return 0;}

執行結果:

$ 。/a。outThis is child process, peter = 10!After child process modify peter = 100This is parent process = 100!

從執行結果中可以看出,當子程序修改了 peter=100 之後,父程序中列印 peter 的值也是100。

使用者態程序/執行緒的建立 fork/vfork/pthread_create

C/C++Linux伺服器開發/後臺架構師【零聲教育】-學習影片教程-騰訊課堂

【文章福利】:小編整理了一些個人覺得比較好的學習書籍、影片資料共享在群檔案裡面,有需要的可以自行新增哦!~點選加入(832218493需要自取)

使用者態程序/執行緒的建立 fork/vfork/pthread_create

pthread_create

現在我們知道了建立程序有兩種方式:fork,vfork。那麼建立執行緒呢?

執行緒的建立介面是用 pthread_create:

#include #include #include #include #include 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 = %d\n”, 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 = %d\n”, getpid(), gettid(), peter); return ret;}

執行結果:

$ 。/a。outcreate thread success!thread_call pid = 9719, tid = 9720, peter = 100process pid = 9719, tid = 9719, peter = 100

從上面的結果可以看出:程序和執行緒的 pid 都是相同的。當執行緒修改了 peter = 100 之後,父程序中列印 peter 的值也是100。

使用者態程序/執行緒的建立 fork/vfork/pthread_create

程序執行緒建立總圖

上面介紹了使用者態建立程序和執行緒的方式,以及各個方式的特點。關於其底層的實現本質,我們後面會詳細講解。這裡先提供一下三者之間的關係,可見三者最終都會呼叫 do_fork 實現。

使用者態程序/執行緒的建立 fork/vfork/pthread_create

但是核心態沒有程序執行緒的概念,核心中只認 task_struct 結構,只要是 task_struct 結構就可以參與排程。