linux子程序知道父程序退出的解決方案
一、關於程序
程序是作業系統進行資源分配和排程的基本單位。linux系統使用fork建立程序,程序pid 0是swapper程序,程序pid 1是init程序,init程序是所有普通使用者程序的父程序。 fork在 <unistd.h>檔案中定義如下: pid_t fork(void); 當fork成功時會返回兩次,一次返回給父程序,一次返回給子程序。 如果fork呼叫成功,返回pid > 0 給父程序,返回pid == 0給子程序。 如果fork呼叫失敗,返回pid == -1給父程序,並且設定errno。二、父程序與子程序的關係
通過fork後,為什麼父程序返回pid > 0,而子程序返回pid == 0呢?這是因為父程序無法知道自己有多少子程序,子程序建立後就獨立於父程序了,無法知道子程序的id。子程序能夠通過getppid獲取父程序的pid。當父程序比子程序提前退出時,子程序會成為孤兒程序,系統會將重置孤兒程序的父程序到init程序ppid == 1。如果子程序提前退出並且父程序沒有使用wait函式監聽處理結束的子程序,那麼該子程序會成為殭屍程序,即系統認為該程序存在,它佔用的程序資訊如程序pid等,會導致系統無法重複利用該pid號,可以這麼理解殭屍程序就是名存實亡的程序,系統認為程序還存在,而子程序已經完成他的執行任務了。三、簡單的程序例程
編譯執行 $ g++ simple_process.cpp $ ./a.out start program ./a.out, pid: 17164, ppid: 8564 parent precess child process, pid: 17165, ppid: 17164 child sleep 0s [[email protected] process-wait]$ child sleep 1s child sleep 2s child sleep 3s child sleep 4s ##child process, pid: 17165, ppid: 1 可以看到,當父程序提前結束時,子程序的父進臣變化為init程序,ppid == 1。#include <cstring> #include <cstdio> #include <cstdlib> #include <unistd.h> #include <errno.h> #include <sys/types.h> #include <sys/wait.h> int main(int argc, char *argv[]) { printf("start program %s, pid: %ld, ppid: %ld \n", argv[0], getpid(), getppid()); pid_t pid = fork(); if (-1 == pid) { printf("fork process failed. errno: %u, error: %s\n", errno, strerror(errno)); exit(-1); } if (pid > 0) { // parent printf("parent precess\n"); sleep(1); /** 標記一、wait 等待子程序結束*/ // int status; // wait(&status); } else { // child printf("child process, pid: %ld, ppid: %ld\n", getpid(), getppid()); for (int i = 0; i < 5; i++) { printf("child sleep %ds\n", i); sleep(1); } printf("##child process, pid: %ld, ppid: %ld\n", getpid(), getppid()); } return 0; }
四、實現父程序監聽子程序執行結束
/** 標記一、wait 等待子程序結束 */
int status;
wait(&status);
編譯
$ g++ simple_process.cpp
$ ./a.out
start program ./a.out, pid: 28989, ppid: 8564
parent precess
child process, pid: 28990, ppid: 28989
child sleep 0s
child sleep 1s
child sleep 2s
child sleep 3s
child sleep 4s
##child process, pid: 28990, ppid: 28989
因為wait函式的作用是等待子程序結束,並獲取子程序結束的狀態,所以父程序wait等待子程序結束後才繼續執行退出,故自程序的ppid一直是原來fork父程序的pid。因為wait函式是阻塞的,所以在實際開發中,需要監聽子程序退出,可以新建執行緒來監聽,並通過回撥函式處理。
五、實現子程序監聽父程序執行結束
fork建立程序以後子程序就成為獨立的執行單位(程序是作業系統資源分配和排程的基本單位),雖然子程序會繼承父程序原來的變數,但是子程序對這些變數的操作不會影響相應父程序變數的值等(這裡只是指簡單的int,long變數,如果是socket,file等共享資源那麼還可能會影響)。子程序已經無法通過普通方式知道父程序的執行狀態(正在執行還是執行結束,程序是否存活)。 子程序要知道父程序的狀態只能通過程序通訊方法解決,常用的程序間通訊:匿名管道,有名管道,訊號量,訊息佇列,訊號,共享記憶體,套接字。 本文將介紹使用套接字實現父程序結束自動結束子程序的方式,主要運用兩個特性。 1)socketpair會產生一個雙向的控制代碼,兩個控制代碼相當於通訊兩端,程式能夠通過一端寫入,然後再另一端控制代碼讀取內容。 2)程序執行退出時系統會自動回收資源,關閉該程序所佔有的檔案控制代碼,套接字控制代碼也是一種控制代碼。 程式碼實現#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <errno.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
void * thr_child(void *arg) {
int sock = *((int*)arg);
char buf[2] = {0};
ssize_t len = 0;
while (-1 == (len = read(sock, buf, sizeof(buf))) && EINTR == errno);
printf("thr_child. pid: %ld, ppid:%ld\n", getpid(), getppid());
exit(-1 == len ? -1 : 0);
}
int main(int argc, char *argv[]) {
printf("start program: %s, pid: %ld, ppid: %ld\n", argv[0], getpid(), getppid());
int fd[2] = {0};
if (-1 == socketpair(PF_LOCAL, SOCK_STREAM, 0, fd)) {
perror("socketpair failed\n");
exit(-1);
}
pid_t pid = fork();
if (-1 == pid) {
perror("fork failed\n");
exit(-1);
}
if (0 == pid) { // child
printf("child process, pid: %ld, ppid: %ld\n", getpid(), getppid());
close(fd[0]);
int sock = fd[1];
pthread_t pid;
if (pthread_create(&pid, NULL, thr_child, (void *)&sock)) {
perror("child. create thread failed\n");
exit(-1);
}
for (int i = 0; i < 20; i++) {
sleep(1);
printf("child sleep: %ds\n", i + 1);
}
} else { // parent
printf("parent process, pid: %ld, ppid: %ld\n", getpid(), getppid());
close(fd[1]);
int sock = fd[0];
for (int i = 0; i < 5; i++) {
sleep(1);
printf("parent sleep: %ds\n", i + 1);
}
}
printf("process %s finish\n", pid > 0 ? "parent" : "child");
return 0;
}
編譯及執行
$ g++ -pthread notify_parent_quit.cpp
$ ./a.out
start program: ./a.out, pid: 31141, ppid: 8564
parent process, pid: 31141, ppid: 8564
child process, pid: 31142, ppid: 31141
parent sleep: 1s
child sleep: 1s
parent sleep: 2s
child sleep: 2s
parent sleep: 3s
child sleep: 3s
parent sleep: 4s
child sleep: 4s
parent sleep: 5s
process parent finish
child sleep: 5s
thr_child. pid: 31142, ppid:1
可以看到,如果使用wait函式,那麼父程序會等待子程序sleep 20秒再自行結束。但是因為父程序結束時會關閉套接字控制代碼sock導致子程序read返回0表示達到檔案結尾,因為父程序沒有主動close套接字控制代碼sock,所以只有父程序退出時由作業系統關閉該控制代碼。上面的notify程式就是運用這點,在父程序結束時通知子程序的。通過執行緒函式thr_child可以知道,線上程退出前列印ppid時,子程序的父程序ppid
== 1,即由於父程序結束導致子程序成為孤兒程序。
總結、socketpair只是其中一種簡單的實現方式。這裡只是使用簡單的例子說明,在實際應用中處理的情況會比較複雜。
相關推薦
linux子程序知道父程序退出的解決方案
在實際開發中難免會處理程序間的關係,最常見的是父子程序的相互監督。父程序等待子程序,或者自程序知道父程序執行是否結束,以方便釋放資源。 一、關於程序 程序是作業系統進行資源分配和排程的基本單位。linux系統使用fork建立程序,程序pid 0是swapper程序,程序pi
linux子程序和父程序的關係
子程序繼承父程序 使用者號UIDs和使用者組號GIDs 環境Environment 堆疊 共享記憶體 開啟檔案的描述符 執行時關閉(Close-on-exec)標誌 訊號(Signal)控制設定 程序組號 當前工作目錄 根目錄
Linux子程序繼承父程序的檔案描述符
/* tcp_server.c */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sys/type
fork -- 子程序共享父程序開啟的檔案描述符
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #define FILE_PATH "file_point" int main(int a
Linux作業系統之PIPE_BUF——父程序讀出資料不相互交叉的問題
問題描述: 常量PIPE_BUF(在limits.h中定義)規定了核心的管道緩衝區大小,為4096byte。 父程序建立的3個子程序同時寫一個管道,要求寫入的位元組數超過PIPE_BUF,父程序從管道讀出的子程序寫入的資料不能相互交叉。 程式碼如下: #inclu
python 開啟程序的兩種方法、以及查詢子程序與父程序
方法1 先輸出主程序,再輸出子程序是因為 p.start() 只是給系統傳送就緒訊號有延時,所以主程序都執行完了,可能子程序才到他開始執行 from multiprocessing import Process # 建立程序的模組 def
fork呼叫後,子程序與父程序是否共享變數
回顧fork呼叫 fork系統呼叫從已存在的程序中生成一個新的程序,這個新的程序就是子程序,我們可以通過fork系統呼叫的返回值來區分子程序還是父程序。 一個程序,包括程式碼、資料和分配給程序的資源。fork()函式通過系統呼叫建立一個與原來程序幾乎完全相
WIN通過子程序獲取父程序ID
// ParentPid.cpp : Defines the entry point for the console application. // 對著你的專案點選右鍵,依次選擇:屬性、配置屬性、常規,然後右邊有個“專案預設值”,下面有個2個MFC的使用選項 #incl
併發伺服器中的fork函式、 子程序與父程序的區別
#include <unistd.h> int fork(void) 返回:在子程序當中為0,在父程序當中表示為子程序ID,若出錯則返回-1 fork函式的特性: 1.fork之前開啟的所有的描述符(檔案描述符、裝置描述符、sockfd、管道中的描述符等等)在f
程序學習——父程序子程序ID
今天在測試共享記憶體時編寫了一個程序測試的程式碼,在呼叫fork函式建立子程序時,在父程序中返回子程序pid,在子程序中返回0;具體程式碼如下: #include <unistd.h> #include <stdio.h> int
關於在使用sparksql寫程序是報錯以及解決方案:org.apache.spark.sql.AnalysisException: Duplicate column(s): "name" found, cannot save to file.
文件加載 mod 但是 路徑 win 錯誤 寫入 技術分享 over 說明: spark --version : 2.2.0 我有兩個json文件,分別是emp和dept: emp內容如下: {"name": "zhangsan", "age": 26, "dep
Python 中子程序與父程序
from multiprocessing import Process import time 複製程式碼 從程式中啟動程序的兩種方式: def task(i): print('%s start!'% i) time.sleep(2) print('%s stop!' % i) 複
獲取Windows程序的父程序編號
Windows API中沒有提供直接獲取指定程序父程序編號的函式。為此可以通過程序快照來遍歷所有程序,從而獲取程序的父程序編號。本文通過NTDLL.dll中未公開API NtQueryInformationProcess來獲取程序的相關資訊,其中就包含了程序的父程序編
框架頁面中,從子頁面重新整理父頁面問題解決
上次做的一個專案的主頁面是那種框架的效果, 左邊點什麼右邊的子頁面對應各個頁面。 我開始要做的功能是當點選某個連線時,且session超時的時候.右邊就出來一個登陸錯誤頁面, 上面有個Button跳轉到登陸頁面。 直接寫的跳轉,就出現了框架巢狀框架的效果- - 後來這一句話
ubuntu中孤兒程序的父程序pid並不是1??
剛剛寫了一個孤兒程序,順手列印了他的ppid,居然發現不是1,什麼鬼??!!! 因為在發現這個結果之前這個程序已經跑了很多遍了,新fork的程序都沒有退出,以為是因為這個原因所以結果跟我想的一樣。 然後sudo reboot,接
Linux PHP安裝遇見的問題及解決方案
linux php安裝出現錯誤 解決方法 遇到的問題與解決方案 問題一:報以下錯誤./configure以下錯誤發生Sorry, I cannot run apxs. Possiblereasons follow:1. Perl is not installed2. apxs was not fou
Linux中yum命令映象源出錯解決方案
好頭疼,最近虛擬機器中的linux系統一直不能安裝東西,只要install就報找不到可用的連結源。。。但是要安裝東西啊,所以就著手解決下。 解決方法:更換源 1.備份 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yu
u盤在linux系統下檔案只讀方式的解決方案
我用的時ubuntu系統,經常使用u盤來傳送檔案,最近不知道為什麼,u盤在window可以正常使用,但是到linux下檔案就變成了只讀方面了,沒法進行復制,貼上了.上網查詢,發現方
[Linux]Ubuntu安裝pip及其各種bug解決方案
原創文章,歡迎轉載。轉載請註明:轉載自 祥的部落格 原文連結:https://blog.csdn.net/humanking7/article/details/84392790 文章目錄 環境 1. 安裝`pip` 2. 檢視`pi
linux下安裝redis出現錯誤及其解決方案
測試於:Redis2.6.17 | CentOS 5.7 安裝: 通過wget方式直接在linux上下載Redis wget http://download.redis.io/releases/red