线程中可以创建进程吗_Linux 进程线程是如何创建的?
生活随笔
收集整理的這篇文章主要介紹了
线程中可以创建进程吗_Linux 进程线程是如何创建的?
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
上文講了《Linux進程在內核眼中是什么樣子的?》,可以理解內核關于進程線程的所有管理就通過一個結構體 —— task_struct。知道了內核眼中進程的描述,本文通過三個例子站在用戶態看下進程線程是如何創建的,不同的創建方式又有哪些優劣?
fork例子
先看一個例子:
#include#include#includeint main() { pid_t pid; int cnt = 0; pid = fork(); if(pid<0) printf("error in fork!\n"); else if(pid == 0) { cnt++; printf("cnt=%d\n",cnt); printf("I am the child process,ID is %d\n",getpid()); } else { cnt++; printf("cnt=%d\n",cnt); printf("I am the parent process,ID is %d\n",getpid()); } return 0; }運行結果為:cnt=1I am the parent process,ID is 15247cnt=1I am the child process,ID is 15248注意,第二個cnt并不是2,為什么會這個結果呢?因為子進程是父進程的副本,它將獲得父進程數據空間、堆、棧等資源的副本。這意味著父子進程間不共享這些存儲空間。內核將復制父進程的地址空間內容給子進程,因此,子進程有了獨立的地址空間。由于在復制時復制了父進程的堆棧段,所以兩個進程都停留在fork函數中,等待返回。因此fork函數會返回兩次,一次是在父進程中返回,另一次是在子進程中返回,這兩次的返回值是不一樣的。調用fork之后,數據、堆棧有兩份,但是代碼段仍然為一份,這個代碼段是兩個進程的共享代碼段,都從fork函數中返回。當父子進程有一個想要修改數據或者堆棧時,兩個進程真正分裂。
fork有兩個特點:- “調用一次,返回兩次”,在父進程中調用一次,在父進程和子進程中各返回一次。
- 所有由父進程打開的描述符都被復制到子進程中。父、子進程中相同編號的文件描述符在內核中指向同一個file結構體,也就是說,file結構體的引用計數要增加。
vfork例子
把上面程序中的fork改成vfork,運行結果是什么樣子的呢?
cnt=1I am the child process,ID is 15385cnt=-486109114I am the parent process,ID is 15384a.out: cxa_atexit.c:100: __new_exitfn: Assertion `l != NULL' failed.Aborted?(core?dumped)咦?為什么會有段錯誤?這是因為沒有調用exec函數,vfork()保證子進程先運行,在它調用exec或exit之后父進程才可能被調度運行。我們把上面的程序修改如下:#include#include#includeint main() { pid_t pid; int cnt = 0; pid = vfork(); if(pid<0) printf("error in fork!\n"); else if(pid == 0) { cnt++; printf("cnt=%d\n",cnt); printf("I am the child process,ID is %d\n",getpid()); _exit(0); } else { cnt++; printf("cnt=%d\n",cnt); printf("I am the parent process,ID is %d\n",getpid()); } return 0; }運行結果如下:cnt=1I am the child process,ID is 15524cnt=2I am the parent process,ID is 15523可見成功執行了,并且cnt是2。因為調用了exec,使得子進程退出,父進程執行,這樣else 后的語句就會被父進程執行,又因在子進程調用exec或exit之前與父進程數據是共享的, 所以子進程退出后把父進程的數據段count改成1 了,子進程退出后,父進程又執行,最終就將cnt變成了2。fork 和?vfork的一些思考
根據上面的例子我們知道 fork 和 vfork 各有優劣,可以用下圖大概描述。
圖片來自網絡fork 要多拷貝一次內存,vfork 用起來又麻煩而且有風險,講真,并不鼓勵用 vfork。那么有沒有辦法對 fork 做個優化,答案是肯定的。目前內核對 fork 做了寫時拷貝(COW)的優化。也就是說,對于fork后并不是立馬拷貝內存,而是只有你在需要改變的時候,才會從父進程中拷貝到子進程中,這樣fork 后立馬執行 exec 的成本就非常小了。clone?創建線程
現在我們知道了創建進程有兩種方式:fork,vfork。那么創建線程呢?
首先得知道什么是進程,什么是線程。有句名言 “進程是資源管理的最小單位,線程是程序執行的最小單位。”?在操作系統設計上,從進程演化出線程,最主要的目的就是減小多進程上下文切換開銷。
因此進程之間共享代碼段,文件描述符,信號處理,全局變量等的話就稱為線程,如果不共享,就是我們所說的進程。
線程的創建接口是用 clone,或者經常用的 pthread_create。進程線程創建總圖
我們先站在上帝視角以一張圖來看下進程線程創建的大體框架,具體的實現下文見。
添加極客助手微信,加入技術交流群
長按,掃碼,關注公眾號
總結
以上是生活随笔為你收集整理的线程中可以创建进程吗_Linux 进程线程是如何创建的?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 机房维护 网拷_机房维护一二三
- 下一篇: android 时间应用程序,Andro