LINUX編程學習筆記(十四) 建立進程與 父子進程記憶體空間

來源:互聯網
上載者:User
文章目錄
  • 1.1 system
  • 1.2 popen:建立子進程
  • 1.3 exec系列函數
  • 1.4 fork
  • 6.2 記憶體映射與子進程:
  • 6.3 檔案描述符的拷貝
1什麼是進程:進程是一個執行中的程式

執行的程式: 代碼->資源->CPU
進程有很多資料維護:進程狀態/進程屬性
所有進程屬性採用的一個樹形結構體維護

ps  -a//所有進程
ps -aue //有效進程

      進程狀態:(man ps)
       D    Uninterruptible sleep (usually IO)
       R    Running or runnable (on run queue)
       S    Interruptible sleep (waiting for an event to complete)
       T    Stopped, either by a job control signal or because it is being traced.
       W    paging (not valid since the 2.6.xx kernel)
       X    dead (should never be seen)
       Z    Defunct ("zombie") process, terminated but not reaped by its parent.
     For BSD formats and when the stat keyword is used, additional characters may be
       displayed:
       <    high-priority (not nice to other users)
       N    low-priority (nice to other users)
       L    has pages locked into memory (for real-time and custom IO)
       s    is a session leader 
       l    is multi-threaded (using CLONE_THREAD, like NPTL pthreads do) 多進程
       +    is in the foreground process group 前台進程

top 即時查看進程
pstree 查看進程樹
kill 向進程發送訊號  kill -s 訊號 進程ID
kill -l  //查看所有訊號
kill -s 9 224  //關閉224進程

2 建立進程1  進程有關的建立函數1.1 system

int system(const char*filename); 
建立一個獨立的進程,擁有獨立的代碼空間
等待新的進程執行完畢,system才返回(阻塞)

使用system調用函數(觀察進程ID 觀察阻塞)
新進程的傳回值和system傳回值有關係
1任何進程的傳回值不要超過255
2 system中進程的傳回值存放在system傳回值的8-15位
可以通過printf("%d\n",r>>8 ); 這樣來獲得傳回值
3 linux中有專用的獲得返回狀態的宏
      WEXITSTATUS(status) //#include<wait.h>  #include <sys/wait.h>

sys.c

#include <stdio.h>#include <unistd.h>int main(){printf("%d\n",getpid());sleep(2);return 254;}sys2.c#include <stdio.h>#include <unistd.h>#include <wait.h>#include <sys/types.h>int main(){int r;printf("%d\n",getpid());r = system("./sleep");//printf("%d\n",r>>8 );printf("%d\n",WEXITSTATUS(r));}

gcc sys.c -o sleep
gcc sys2.c 
./a.out

1.2 popen:建立子進程

FILE *popen(const char *command, const char *type);

int pclose(FILE *stream);

案例:使用popen調用ls -l 並且建立一個管道讀取輸出

#include <stdio.h>#include <unistd.h>int main(){FILE *fp = popen("cat file","r"); //注意這裡是讀取輸出,不是開啟檔案 不能直接寫檔案名稱//FILE *fp = popen("ls -l","r");if(!fp){perror("popen");return 1;}int fd = fileno(fp);int r;char buf[1024] = {0};while((r=read(fd,buf,1023)) > 0){buf[r] = 0;printf("%s",buf);}pclose(fp);}


1.3 exec系列函數

       int execl(const char *path, const char *arg, ...);
       int execlp(const char *file, const char *arg, ...);
       int execle(const char *path, const char *arg,
                  ..., char * const envp[]);
       int execv(const char *path, char *const argv[]);
       int execvp(const char *file, char *const argv[]);

作用: 替換當前代碼空間中的資料
函數本身不建立新的進程
第一個參數:替換的程式 
第二個參數:
命令列
命令列格式:命令名 選項參數 NULL
命令列結尾必須是Null 字元串

execl execlp的區別:
execl   只在當前路徑搜尋
execlp 可以使用系統搜尋路徑(which能找到)
如果都找不到,可以使用絕對路徑

命令鎖指向的程式  命令本身 參數列表
如果返回-1  失敗

#include <stdio.h>int main(){int r = execl("/bin/ls","ls","-l",0); // 只能調用當前路徑//int r = execlp("ls","ls","-l",0);// 能調用系統路徑  printf("調用結束%d\n",r);return 0;}
1.4 fork

pid_t fork()

1 建立進程
2 新進程的代碼是什麼:複製父進程的挨罵
而且複製來執行的位置
3 在子進程中不調用fork 所有傳回值=0
4 父子進程同時執行

#include <stdio.h>#include <unistd.h>int main(){printf("建立進程前\n");int pid = fork(); //父進程執行的while(1){if(pid == 0){printf("子進程 %d\n",getpid());}else{printf("父進程 %d\n",getpid());}}}

3 應用進程

使用fork實現多任務(unix本身是不支援線程的)
1 進程
2 線程
3 訊號
4 非同步
5 進程池與線程池

4 理解進程

1父子進程的關係
獨立的兩個進程
互為父子關係
使用pstree看到
     ├─gnome-terminal─┬─bash───a.out───a.out //父子關係
     │                ├─bash───pstree
     │                ├─gnome-pty-helpe
     │                └─2*[{gnome-terminal}]

2 問題:
1如果父進程先結束 子進程在麼辦
子進程將變成孤兒進程,直接依託根進程(init)
孤兒 進程是沒有危害的

init─┬─NetworkManager─┬─dhclient
│                └─{NetworkManager}
├─a.out

2 如果子進程先結束 父進程怎麼辦
子進程先結束,子進程會成為殭屍進程。
殭屍進程的特點: 不佔用記憶體 cpu,但在進程任務管理樹上佔用一個節點(寶貴)
       實際上殭屍進程會造成進程名額的資源浪費。一定要處理殭屍進程
   ├─gnome-terminal─┬─bash───pstree
  │                ├─bash───a.out───a.out

3 殭屍進程使用wait回收(阻塞函數)
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
wait 阻塞直到任意進程結束,status來接收進程傳回值,傳回值表示返回的進程號
waitpid 阻塞直到指定進程結束

WEXITSTATUS(status) 解析傳回值  status的 8-15位是進程的傳回值

4 父進程怎麼知道子進程退出?
子進程結束時,通常會向父進程發送一個SIGCHLD訊號

5父進程處理子進程的訊號
#include <signal.h>
       typedef void (*sighandler_t)(int);
       sighandler_t signal(int signum, sighandler_t handler);
signal 的功能 :
向系統註冊,只要接收到訊號signal,系統停止進程,執行handler函數,
當函數執行完畢,繼續原來的進程 (非強制中斷)
5.1實現處理函數
5.2 使用signal綁定訊號與函數

只有當子進程退出時才用wait,因為wait是一個阻塞函數。所以wait和signal一起用。

#include <stdio.h>#include <unistd.h>#include <sys/wait.h>#include <sys/types.h>#include <signal.h>void deal(int s){printf("回收中\n");sleep(5);int status;wait(&status);printf("回收完畢%d\n",WEXITSTATUS(status));}int main(){printf("建立進程前\n");int pid = fork(); //父進程執行的if(pid == 0){printf("子進程 %d\n",getpid());sleep(5);return 88;}else{printf("父進程 %d\n",getpid());signal(SIGCHLD,deal);while(1){sleep(1);printf("parent\n");}return 0;}}


zhao@ubuntu:~/unix/5$ ./a.out 
建立進程前
父進程 2324
子進程 2325
parent
parent
parent
parent
回收中
回收完畢88
parent
parent
parent
^C

6 父子進程的記憶體空間

6.1 全域變數 局部變數 堆變數 都會被子進程拷貝,但與原先的獨立。

注意 堆記憶體被複製了,需要分別在各個進程中手動釋放。

子進程複製了父進程的全域區和局部區記憶體,但記憶體地區指向不同的物理空間。
儘管複製但記憶體獨立,不能相互訪問。
處理序間通訊(IPC)是大問題。

6.2 記憶體映射與子進程:

記憶體映射的屬性,決定子進程和父進程是否映射在同一物理空間。
MAP_SHARED: 映射到同一物理空間。 (改一個進程中的,其他進程的也變化)
MAP_PRIVATE:映射到不同的物理空間。

#include <stdio.h>#include <unistd.h>#include <sys/mman.h>int main(){int *a = mmap(0,4,PROT_READ|PROT_WRITE,      MAP_ANONYMOUS|MAP_SHARED,0,0);*a = 20;int pid = fork(); //父進程執行的if(pid == 0){*a= 90;printf("parent :a=%d\n",*a);//90}else{sleep(3);printf("child :a=%d\n",*a);//90}}

因為使用的是MAP_SHARED ,所以射到了同一物理空間, 改動會影響其它的.

若使用MAP_PRIVATE 就可以映射到不同物理空間.

6.3 檔案描述符的拷貝

每個進程都維護一個檔案描述符列表。
父子進程間,拷貝了檔案描述符, 相同檔案描述符指向的是同一個檔案核心對象。
1 各個進程的檔案描述符都需要close。
2 對檔案的讀寫會改變檔案對象的讀寫指標位置,對所有進程都有影響。

#include <stdio.h>#include <unistd.h>#include <sys/mman.h>#include <fcntl.h>int main(){int fd = open("test.txt",O_RDWR);int pid = fork(); //父進程執行的if(pid == 0){printf("parent:\n");char buf[1024] ={0};lseek(fd,0,SEEK_SET);read(fd,buf,1023);printf("%s\n",buf);close(fd);}else{printf("child:\n");char buf[1024] ={0};lseek(fd,0,SEEK_SET);read(fd,buf,1023);printf("%s\n",buf);close(fd);}}

進程的資料交換,基於兩種方式:
記憶體: 有序/無序:mmap
檔案:有序/無序:普通檔案
基於核心對象:檔案/記憶體/隊列

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.