1. 程式人生 > >Linux -- 程序間關係和守護程序

Linux -- 程序間關係和守護程序

1, 程序組(Process Group)

每個程序除了有一個程序ID之外,還屬於一個程序組。
程序組是一個或多個程序的集合。
通常,它們與同一 作業 相關聯,可以接收來自同一終端的各種訊號。
每個程序組有一個唯一的程序組ID。每個程序組都可以有一個組長程序。
組長程序的標識是,其程序組ID等於其程序ID。
組長程序可以建立一個程序組,建立該組中的程序,然後終止。
只要在某個程序組中有一個程序存在,則該程序組就存在,這與其組長程序是否終止無關。
例項如下:

ps axj | head -n1 
ps axj | grep sleep | grep -v grep

這裡寫圖片描述


& 表示將程序組放在後臺執行
程序 2859
程序 2860
程序 2861
程序組長是程序 2859, 所以程序組 ID (PGID)就是2859
kill -9 殺掉組長
這裡寫圖片描述
程序組還在

ps選項:

  • a: 不僅列出當前使用者的程序,也列出所有其他使用者的程序
  • x: 表示不僅列出有控制終端的程序,也列出所有無控制終端的程序
  • j: 表示列出與作業控制相關的資訊

2, 作業(Job)

實際上,Shell分前後臺來控制的不是程序而是作業(Job)或者程序組(Process Group)。
一個前臺作業可以由多個程序組成,一個後臺作業也可以由多個程序組成,Shell 可以執行一個前臺作業和任意多個後臺作業,這稱為作業控制 。

作業與程序組的區別:
如果作業中的某個程序又建立了子程序,則子程序不屬於作業。
一旦作業執行結束,Shell就把自己提到前臺(子程序還在,可是子程序不屬於作業)
如果原來的前臺程序還存在(如果這個子程序還沒終止),它自動變為後臺程序組。 在前臺新起作業,Shell是無法執行,因為他被提到了後臺。 但是如果前臺程序退出, Shell就又被提到了前臺,所以可以繼續接受使用者輸入。

示例

/*================================================================
  Copyright (C) 2018 RJM. All rights reserved.
# File Name: test.c
# Author: rjm # mail: [email protected] # Created Time: 2018年04月25日 星期三 12時06分08秒 ================================================================*/ #include <stdio.h> #include <unistd.h> int main() { pid_t id = fork(); if(id == 0) { //child while(1) { printf("i am child: %d, i am runing\n", getpid()); sleep(1); } } else { //father int i = 5; while(i) { printf("i am father: %d\n", getpid()); i--; } sleep(1); } return 0; }

這裡寫圖片描述
程式執行,在前臺新起了一個作業,這時shell無法接收命令,說明shell被切到了後臺
5s 之後, 父程序退出, shell可以接收命令,說明此時shell是前臺作業,但是此時子程序仍存在,並且還在一直列印訊息(可以用 kiil -9 殺掉)
雖然他在還列印訊息,但是他是後臺程序,無法接受鍵盤輸入,只能往螢幕上列印,也就是說只能寫不能讀。此時輸入命令雖然會被子程序列印的訊息衝亂,但其實他們仍是連續的命令,可以執行。
這裡寫圖片描述
可以看到雖然父程序退出了, 但程序組還在, PGID是3088,此時子程序變孤兒了,可以看到他被 1號程序領養了。

3, 會話(Session)

會話(Session)是一個或多個程序組的集合。
一個會話可以有一個控制終端。這通常是登陸到其上的終端裝置(在終端登陸情況下)或偽終端裝置(在網路登陸情況下)。
建立與控制終端連線的會話首程序被稱為 控制程序
一個會話中的幾個程序組可被分為一個前臺程序組以及一個或多個後臺程序組。
所以一個會話中,應該包括控制程序(會話首程序),一個前臺程序組和任意後臺程序組
這裡寫圖片描述
SID(會話 ID)是2610, 三個程序都屬於同一個程序組,同一個會話 ,他們的父程序也都是2610
那麼2610 是誰呢?
可以看到2610就是 bash,也就是我們的直譯器,會話首程序。
多開啟幾個終端,對比你就會發現,每開啟一個終端,就新建了一個會話

這裡寫圖片描述

可以看到我們打開了 4 個會話,前3個是用xhell網路登陸的,後面是 - bash
最後一個是直接終端登入的,後面是 bash

4, 作業控制

Shell可以同時執行一個前臺程序和任意多個後臺程序”其實是不全面的
事實上,Shell分前後臺來控制的不是程序而是作業 (Job)或者程序組(Process Group)
一個前臺作業可以由多個程序組成,一個後臺作業也可以由多個程序組成,Shell可以同時執行一個前臺作業和任意多個後臺作業,這稱為作業控制(Job Control)
這裡寫圖片描述

jobs     //檢視後臺執行的程式及執行狀態
fg 1     //將後臺的程式調到前臺
ctrl + z //是暫停當前正在前臺執行的程式
bg 1     //將剛才暫停的程式放到後臺,並讓其執行

這裡寫圖片描述
ctrl + c 殺掉的不是程序,而是整個作業

作業控制有關的訊號

這裡寫圖片描述
將cat放到後臺執行,由於cat需要讀標準輸入(也就是終端輸入),而後臺程序是不能讀終端輸入的,因此核心發 21號訊號 SIGTTIN 給該程序,該訊號的預設處理動作是使程序停止(而不是終止退出),將cat 提到前臺依然可以執行
這裡寫圖片描述

jobs命令可以檢視當前有哪些作業
fg命令可以將某個作業提至前臺執行
如果該作業的程序組正在後臺執行 則提至前臺執行
如果該作業處於停止狀態,則給程序組的每個程序發SIGCONT訊號使它繼續執行
引數1表示將第1個作業提至前臺執行。
cat提到前臺執行後,掛起等待終端輸入,當輸入hello並回車後,cat打印出同樣的一行,然後繼續掛起等待輸入。
如果輸入Ctrl-Z則向所有前臺程序發SIGTSTP訊號,該訊號的預設動作是使程序停止,cat繼續以後臺作業的形式存在。
bg命令可以讓某個停止的作業在後臺繼續執行,也需要給該作業的程序組的每個程序發SIGCONT訊號。cat程序繼續執行,又要讀終端輸入,然而它在後臺不能讀終端輸入,所以又收到SIGTTIN訊號而停止
這裡寫圖片描述
kill 命令給一個停止的程序發 SIGTERM(15) 訊號,這個訊號並不會立刻處理,而要等程序準備繼續執行之前處理,預設動作是終止程序。但如果給一個停止的程序發SIGKILL訊號就不同了

5, 守護程序

守護程序也稱精靈程序(Daemon)
是執行在後臺的一種特殊程序。它獨立於控制終端並且週期性地執行某種任務或等待處理某些事件。
守護程序是一種很有用的程序。Linux的大多數伺服器就是用守護程序實現的。
比如,ftp伺服器,ssh伺服器,Web伺服器httpd等。
同時,守護程序完成許多系統任務。
比如,作業規劃程序crond等。
Linux系統啟動時會啟動很多系統服務程序,這些系統服務程序沒有控制終端,不能直接和使用者互動。其它程序都是在使用者登入或執行程式時建立,在執行結束或使用者登出時終止。
但系統服務程序(守護程序)不受使用者登入登出的影響 ,它們一直在執行著。

下面我們用ps axj命令檢視系統中的程序

  • 引數 a 表示不僅列出當前使用者的程序,也列出所有其他使用者的程序
  • 引數 x 表示不僅列出有控制終端的程序,也列出所有無控制終端的程序
  • 引數 j 表示列出與作業控制相關的資訊
ps axj | more

這裡寫圖片描述
凡是TPGID一欄寫著 -1 的都是沒有控制終端的程序,也就是守護程序。
在COMMAND一列用 [ ] 括起來的名字表示核心執行緒,這些執行緒在核心裡建立,沒有使用者空間程式碼
因此沒有程式檔名和命令列, 通常採用以k開頭的名字,表示Kernel
init程序我們已經很熟悉了
udevd 負責維護/dev目錄下的裝置檔案
acpid負責電源管理
syslogd負責維護/var/log下的日誌檔案
可以看出,守護程序通常採用以d結尾的名字,表示Daemon

建立守護程序

建立守護程序最關鍵的一步是呼叫setsid函式建立一個新的Session
併成為Session Leader

#include <unistd.h> 
pid_t setsid(void); 
//該函式呼叫成功時返回新建立的Session的id(其實也就是當前程序的id)
//出錯返回-1

注意, 呼叫這個函式之前 , 當前程序不允許是程序組的 Leader, 否則該函式返回 -1

要保證當前程序不是程序組的Leader也很容易,只要先fork再呼叫setsid就行了fork建立的子程序和父程序在同一個程序組中,程序組的 Leader必然是該組的第一個程序,也就是父程序,所以子程序不可能是該組Leader,在子程序中呼叫setsid就不會有問題了
成功呼叫該函式的結果是
建立一個新的Session,當前程序成為Session Leader,當前程序的id就是Session的id
建立一個新的程序組,當前程序成為程序組的Leader,當前程序的id就是程序組的id
如果當前程序原本有一個控制終端,則它失去這個控制終端,成為一個沒有控制終端的程序。
所謂失去控制終端是指,原來的控制終端仍然是開啟的,仍然可以讀寫,但只是一個普通的開啟檔案而不是控制終端了。

建立程式碼

#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>

void mydaemon(void)
{
    int i;
    int fd0;
    pid_t pid;
    struct sigaction sa;
    //1. 呼叫umask將檔案模式建立遮蔽字設定為0.
    umask(0); 

    //2. 呼叫fork, 父程序退出(exit), 保證子程序不是一個程序組的組長程序。
    //   如果該守護程序是作為一條簡單的shell命令啟動的
    //   那麼父程序終止使得shell認為該命令已經執行完畢
    if( (pid = fork()) < 0 )
    {
        perror("fork");
    }
    else if (pid > 0)
    {
        exit(0);
        //終止父程序
    }
    //3. 呼叫setsid建立一個新會話
    setsid(); 
    //4. 忽略SIGCHLD訊號
    sa.sa_ handler = SIG_IGN;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    if( sigaction(SIGCHLD, &sa, NULL ) < 0 )  // 註冊子程序退出忽略訊號
    {
        return;
    }

    //5.將當前工作目錄更改為根目錄。
    if( chdir("/") < 0 )
        printf("child dir error\n");
    return;

    //關閉不需要的檔案描述符,或者重定向到 /dev/null
    close(0);
    fd0 = open("/dev/null", O_RDWR);
    dup2(fd0, 1);
    dup2(fd0, 2);
}

int main()
{
    mydaemon();
    while(1)
    {
        sleep(1);
    }
}

這裡寫圖片描述
可以看到我們建立了自己的守護程序

實際上,系統已經提供了專門建立守護程序的函式

daemon函式

int daemon(int nochdir,int noclose);

建立守護程序的時候,往往要做以下兩件事情

  • 1.將程序的工作目錄修改為”/”根目錄
    daemon的引數nochdir為0時,即可將工作目錄修改為根目錄;
  • 2.將標準輸入,輸出和錯誤輸出重定向到/dev/null
    daemon的引數noclose為0時,輸入,輸出以及錯誤輸出重定向到/dev/null
#include <stdio.h> 
#include <unistd.h> 
int main() 
{    
    daemon(0,0);    
    while(1); 
}

相關推薦

Linux -- 程序關係守護程序

1, 程序組(Process Group) 每個程序除了有一個程序ID之外,還屬於一個程序組。 程序組是一個或多個程序的集合。 通常,它們與同一 作業 相關聯,可以接收來自同一終端的各種訊號。 每個程序組有一個唯一的程序組ID。每個程序組都可以有一個組長

Linux程序關係守護程序

程序間關係 程序組/作業/會話 程序組 程序組是一個或多個程序的集合,通常它們與一組作業相關聯,可以接受來自同一終端的各種訊號。 每個程序除了有一個程序ID之外,還屬於一個程序組。 每個程序組都有唯一的程序組ID(整數,也可以存放在pid_t型別

Linux程序關係守護程序

概念 守護程序也稱精靈程序,是執行在後臺的一種特殊程序。守護程序獨立於控制終端並且週期性的執行某種任務或者等待處理某些打算的事件。可認為守護程序目的就是防止終端產生的一些訊號讓程序退出 特點 所有的守護程序都沒有控制終端,其終端名(TTY)設定為問號(?

Linux 程序】孤兒程序、殭屍程序守護程序

1、孤兒程序: 孤兒程序:一個父程序退出,而它的一個或多個子程序還在執行,那麼那些子程序將成為孤兒程序。孤兒程序將被init程序(程序號為1)所收養,並由init程序對它們完成狀態收集工作。孤兒程序是沒有父程序的程序,孤兒程序這個重任就落到了init程序身上,init程序就好像是一個民政局,專門負責處理孤兒

docker cli守護程序關係

Docker並非單體應用,它由多個元件構成。介紹Docker守護程序(daemon)與Docker命令列(CLI)。事實上,當我們在談論安裝或使用Docker時,所指的其實就是Docker守護程序與命令列。 Docker守護程序(docker daemon)是

程序通訊執行緒同步區別

執行緒間通訊:由於多執行緒共享地址空間和資料空間,所以多個執行緒間的通訊是一個執行緒的資料可以直接提供給其他執行緒使用,而不必通過作業系統(也就是核心的排程)。 程序的通訊機制主要有:管道、有名管道、訊息佇列、訊號量、共享空間、訊號、套接字。 linux中程序間通訊和執行緒間通訊的區別:

Linux 多執行緒程序的區別(小結)

最近學習Linux,看到“hairetz的專欄”的帖子不錯,特轉來大家一起學習。 很想寫點關於多程序和多執行緒的東西,我確實很愛他們。但是每每想動手寫點關於他們的東西,卻總是求全心理作祟,始終動不了手。 今天終於下了決心,寫點東西,以後可以再修修補補也無妨。一.為何需要多程序(或者多執行緒),為何需

安卓多執行緒通訊程序之間通訊有什麼不同?分別怎麼實現?

**當一個程式第一次啟動的時候,Android會去動一個Linux進行和一個主執行緒,預設情況下,所有改程式元件都將在該程序和執行緒中 執行,同時Android會為每個應用程式分配一個單獨的Linux使用者,Android會盡量保留一個正在執行的程序,只在記憶體資源出現不足時,Andro

守護執行緒守護程序

守護程序隨著主程序的程式碼的執行結束而結束 守護執行緒會在主執行緒結束之後等待其他子執行緒的結束才結束(如有其他子執行緒,沒有其他子執行緒就是主執行緒結束守護執行緒隨之結束) import time from threading import Thread def func1(): whi

rsync增量複製命令用法守護程序的配置

實驗系統 rhel6.5 從本地到本地           《========》  cp rsync -avz  src  dst rsync -avz sr

關於GOGS的鉤子守護程序

Gogs是什麼呢?官方的說法是:Gogs 是一款極易搭建的自助 Git 服務。 那麼看完了之後,依然一頭霧水,這說的是啥????? 我們知道使用git的時候,遠端庫可以用github,或者自己Linux伺服器安裝git以後,建立一個自己的倉庫,無論是github的遠端倉庫

RHCE——控制服務守護程序

識別自動啟動的系統程序 系統啟動的伺服器程序由systemd系統和伺服器管理器進行管理 systemctl可以縮寫或者省略單元名稱、進度數條目和單元說明 服務單元具有.service副檔名,代表系統服務 套接字單元具有.socket副檔名,代表程序之間通

ASP.NET Core Linux下為 dotnet 建立守護程序(必備知識)

前言 在上篇文章中介紹瞭如何在 Docker 容器中部署我們的 asp.net core 應用程式,本篇主要是怎麼樣為我們在 Linux 或者 macOs 中部署的 dotnet 程式建立一個守護程序,來保證我們的程式在異常或者是電腦重啟的時候仍然能夠正常訪問。 如果你以後用準備使用 asp.net core

作業系統——程序通訊排程

1.程序間排程 程序經常需要與其他程序通訊,就比如shell中的管道,一個程序的輸出通過管道傳給第二個程序。程序間通訊簡要來說,有三個問題,程序如何把資訊傳遞給另一個,如何確保兩個或更多的程序在關鍵活動中不會出現交叉,此外還需要保證程序執行的順序性。 1.1競爭條件 作業系統中協作的程序可能共享

spring cloud快速入門教程(六)程序呼叫微服務負載均衡(Feign)

RestTemplate是不是很簡單粗暴呢?還有更粗暴的,那就是Feign,很多人都用過Dubbo,Feign的用法跟他類似。 我們複用userService那個module去呼叫productService微服務中的getProduct介面,引入Feign的依賴包: &

Android程序通訊執行緒通訊

程序間和執行緒間通訊 這個知識點算是高階知識點, 執行緒和程序 首先要區分執行緒和程序的區別: 執行緒是cup最小排程單元; 程序是一系列執行緒的集合。 其實區分程序和執行緒通訊有一個很好的方法:程式是否重新起了一個虛擬機器,因為不同程序會啟動不

RHEL七(控制服務守護程序

rhel5、rhel6中控制服務使用service、chkconfig命令,在rhel7中被systemctl取代,rhel7中在一定程度上仍然可以使用service、ckconfig,但推薦使用sy

Linux守護程序以及實現一個守護程序

1、什麼是守護程序 守護程序也稱為精靈程序,是執行在後臺程序的一種特殊程序。它獨立於控制終端並且週期性地執行某種任務或等待處理某些發生的事件。 (1)脫離於控制終端並且在後臺執行 (2)不受使用者登入登出的影響,它們一直在執行著 Linux大多數伺服器就

學習筆記之linux多執行緒程序優缺點

Linux下的多執行緒 執行緒和程序相比的缺點和優點 優點: 多執行緒對資源的需求少,建立的代價比程序小 缺點:除錯困難,非常容易出錯 執行緒擁有獨立的程式計數器,獨立的棧空間,共享程序的全域性記憶體和堆記憶體,共享檔案描述符,共享虛擬記憶體。繼承訊號的處理可以訪問程序