wordpress 換域名 全站301重定向百度熱搜榜小說排名
0202 Linux進程資源
?專欄內(nèi)容:
- postgresql使用入門基礎(chǔ)
- 手寫數(shù)據(jù)庫toadb
- 并發(fā)編程
個人主頁:我的主頁
管理社區(qū):開源數(shù)據(jù)庫
座右銘:天行健,君子以自強不息;地勢坤,君子以厚德載物.
文章目錄
- 0202 Linux進程資源
- 一、概述
- 二、資源創(chuàng)建場景
- 三、資源在子進程中創(chuàng)建
- 3.1 示例代碼
- 3.2 進程獨立驗證
- 四、程序啟動時資源創(chuàng)建
- 4.1 示例代碼
- 4.2 共用內(nèi)核對象
- 總結(jié)
- 結(jié)尾
一、概述
進程啟動之后,除了占用內(nèi)存資源之外,在進程中還會打開文件,共享內(nèi)存,網(wǎng)絡(luò)套接字等與內(nèi)核對象關(guān)聯(lián)的資源,
這些資源在子進程中如何處理呢?
本節(jié)以文件為例,分析父子進程間對于與內(nèi)核相關(guān)聯(lián)的資源的處理情況,并使用代碼實例進行演示。
二、資源創(chuàng)建場景
在使用fork創(chuàng)建子進程的時刻,對資源的使用大致分為兩類情況:
- 也可能是運行了一段程序,初始化很多資源;然后再創(chuàng)建多進程任務(wù);
此時,子進程會繼承父進程創(chuàng)建的資源;
同時,要在子進程中關(guān)閉和釋放不再使用的資源,否則會產(chǎn)生資源泄漏;
- 也可能是剛開始運行,先創(chuàng)建多任務(wù),然后根據(jù)不同任務(wù)的分工不同,再初始化各自的資源;
此時,各子進程中沒有繼承的資源;
在第一類場景下,對于關(guān)聯(lián)內(nèi)核對象的資源,繼承后的特性也會與單進程使用有一定區(qū)別,下面通過案例來分析一下。
三、資源在子進程中創(chuàng)建
資源在fork之后創(chuàng)建,也就是在子進程中創(chuàng)建。
這種情況與我們常規(guī)編寫一個main函數(shù)中創(chuàng)建類似,也就是單進程程序一樣,各子進程間互相獨立,沒有聯(lián)系。
3.1 示例代碼
- 下面通過一段測試代碼來演示一下:
/** ex020104_forkafter.c*/
#include <stdio.h>#include <sys/types.h>
#include <unistd.h>#include <errno.h>
#include <string.h>typedef struct Info
{int pid;int seg;
}Info;FILE *fp = NULL;
int segno = 0;void OpenFile(char *path);
void CloseFile();
void ReadFile();
void WriteFile();int main(int argc ,char *argv[])
{int pid = -1;pid = fork();if(pid == 0){OpenFile("test");// in child printf("here in child ,my pid is %d\n", getpid());WriteFile();sleep(5);WriteFile();sleep(5);WriteFile();}else if(pid > 0){OpenFile("test");// in parentprintf("here in parent, my pid %d, child pid is %d\n", getpid(), pid);sleep(3);ReadFile();sleep(5);ReadFile();sleep(5);ReadFile();}else{// errorprintf("fork error[%s]\n",strerror(errno));}CloseFile();return 0;
}
在創(chuàng)建子進程之后,父子進程中同時打開test
文件,進行以下步驟:
- 子進程從文件頭寫入結(jié)構(gòu)體數(shù)據(jù);
- 父進程從文件頭讀一個結(jié)構(gòu)體大小的數(shù)據(jù);
- 然后子進程在上次偏移位置繼續(xù)寫入結(jié)構(gòu)體大小的數(shù)據(jù);
- 接著父進程從自己的偏移位置處讀入結(jié)構(gòu)體數(shù)據(jù);
- 繼續(xù)一次步驟3和4;
- 在進程結(jié)束時,關(guān)閉文件。
公共的文件操作函數(shù)
為了方便多次測試,將打開文件,關(guān)閉文件,讀寫文件編寫為公共函數(shù)。
void OpenFile(char *path)
{if(NULL == path)return;fp = fopen(path, "w+");if(NULL == fp){printf("open file %s error!\n", path);}return;
}void CloseFile()
{if(NULL != fp)fclose(fp);
}void ReadFile()
{Info rinfo = {0};int pos = 0;if(NULL == fp)return ;/* data read from current position record by the fp. */pos = ftell(fp);fread(&rinfo, sizeof(rinfo), 1, fp); printf("[%d] read from %d, context(%d, %d) \n", getpid(), pos, rinfo.pid, rinfo.seg);
}void WriteFile()
{Info winfo = {0};int pos = 0;if(NULL == fp)return ;winfo.seg = segno++;winfo.pid = getpid();/* data read from current position record by the fp. */pos = ftell(fp);fwrite(&winfo, sizeof(winfo), 1, fp); fflush(fp);printf("[%d] write to %d, context(%d, %d) \n", getpid(), pos, winfo.pid, winfo.seg);
}
3.2 進程獨立驗證
- 編譯運行:
[senllang@hatch ex_0201]$ gcc ex020104_forkafter.c -o extest
[senllang@hatch ex_0201]$ ./extest
here in parent, my pid 802470, child pid is 802471
here in child ,my pid is 802471
[802471] write to 0, context(802471, 0)
[802470] read from 0, context(802471, 0)
[802471] write to 8, context(802471, 1)
[802470] read from 8, context(802471, 1)
[802471] write to 16, context(802471, 2)
[802470] read from 16, context(802471, 2)
- 結(jié)果分析
- 可以看到進程
802471
從文件偏移為0處開始寫入數(shù)據(jù);- 而父進程
802470
也是從偏移為0處讀數(shù)據(jù);- 兩個進程的偏移都是各自計數(shù),互相獨立;文件偏移記錄在內(nèi)核文件表項中;
四、程序啟動時資源創(chuàng)建
如果在程序啟動時創(chuàng)建文件,也就是在fork之前創(chuàng)建,子進程會繼承之前創(chuàng)建的文件句柄。
在這種情況下,會出現(xiàn)什么樣的情況呢?
4.1 示例代碼
/** ex020103_forkresource.c*/
#include <stdio.h>#include <sys/types.h>
#include <unistd.h>#include <errno.h>
#include <string.h>typedef struct Info
{int pid;int seg;
}Info;FILE *fp = NULL;
int segno = 0;void OpenFile(char *path);
void CloseFile();
void ReadFile();
void WriteFile();int main(int argc ,char *argv[])
{int pid = -1;OpenFile("test");pid = fork();if(pid == 0){// in child printf("here in child ,my pid is %d\n", getpid());WriteFile();sleep(5);WriteFile();sleep(5);WriteFile();}else if(pid > 0){// in parentprintf("here in parent, my pid %d, child pid is %d\n", getpid(), pid);sleep(3);ReadFile();sleep(5);ReadFile();sleep(5);ReadFile();}else{// errorprintf("fork error[%s]\n",strerror(errno));}CloseFile();return 0;
}
這段代碼與前例類似,只是將創(chuàng)建文件放在了fork之前,
也就是FILE *fp 在主程序中先被初始化了,然后創(chuàng)建了子進程,在子進程中引用了一模一樣的內(nèi)容,類似于拷備了一份。
4.2 共用內(nèi)核對象
- 編譯運行
[senllang@hatch ex_0201]$ gcc ex020103_forkresource.c -o extest1
[senllang@hatch ex_0201]$ ./extest1
here in parent, my pid 803877, child pid is 803878
here in child ,my pid is 803878
[803878] write to 0, context(803878, 0)
[803877] read from 8, context(0, 0)
[803878] write to 8, context(803878, 1)
[803877] read from 16, context(0, 0)
[803878] write to 16, context(803878, 2)
[803877] read from 24, context(0, 0)
可以看到很有意思的現(xiàn)象:
- 在子進程
803878
中,在文件偏移0處寫入,之后偏移變?yōu)?; - 而之后父進程
803877
開始讀時,文件偏移為8,并沒有從0開始; - 接著子進程
803878
又從偏移8處寫入數(shù)據(jù),之后偏移變?yōu)?6; - 而父進程
803877
讀偏移也變成了16; - 后面一次,也是父進程中文件偏移,與子進程中文件偏移相互聯(lián)系;
總結(jié)
好了,到這里,子進程是父進程的拷貝有了更加深入的理解,這里像編程語言中的深拷貝與淺拷貝的關(guān)系。
而子進程其實是做了一些淺拷貝,引用的內(nèi)核文件表項還是一份,這就會引起兩個進程共同操作的問題。
在這種情況下,每次操作需要加鎖,同時要指定操作的位置和大小。
結(jié)尾
非常感謝大家的支持,在瀏覽的同時別忘了留下您寶貴的評論,如果覺得值得鼓勵,請點贊,收藏,我會更加努力!
作者郵箱:study@senllang.onaliyun.com
如有錯誤或者疏漏歡迎指出,互相學(xué)習(xí)。
注:未經(jīng)同意,不得轉(zhuǎn)載!