gunicorn進程管理源碼解析

1、參考

github gunicorngit

wiki signalgithub

What-is-SIGCHLD-in-Linuxweb

2、信號

2.1 POSIX標準的信號

2.1.1 基本介紹

image.png

SIGCHID: signal childshell

當子進程終止、被中斷或者被中斷後恢復,SIGCHID信號被髮送到父進程,該信號的常見用法是:指示操做系統在子進程終止後,清理子進程使用的資源django

SIGHUB: signal hangup安全

當控制終端被關閉時候,SIGHUB信號被髮送到父進程,它最初設計用於通知串行線路中斷(掛斷)的過程,在現代操做系統中,SIGHUB信號一般意味着控制僞終端或者虛擬終端已經被關閉,許多守護進程在接到該信號後,將會從新加載它們的配置文件而且從新打開它們的日誌文件,一般不會在收到信號後,退出。使用NOHUP命令會忽略該信號。ui

注:例如,django web開發環境,直接使用nohup 命令開啓服務,關閉終端不會影響到web server服務spa

SIGQUIT: signal quit操作系統

QUIT字符(一般是Ctrl-來控制)觸發,進程在收到SIGQUIT信號退出時候會產生core文件,在這個意義上相似於一個程序錯誤信號設計

SIGINT: signal interrupt
當用戶但願中斷進程時候,在控制終端按下INTE字符(一般是Ctrl+C)後,控制終端將發送信號SIGINT到其餘進程

SIGTERM: signal termination

terminal信號被髮送到進程以請求其終止,與SIGKILL信號不一樣,它能夠被進程捕獲,解釋或者忽略,這容許進程在合適的狀況下執行良好的終止釋放資源和保存狀態,SIGINTSIGTERM幾乎相同
程序結束信號,與SIGKILL不一樣的是該信號能夠被阻塞和處理,一般用於要求程序本身正常退出,shell命令kill不帶參數,將產生這個信號,若是進程終止不了,纔會嘗試SIGKILL

SIGKILL: signal kill

kill信號被髮送到某個進程,使得該進程當即終止,和SIGTERMSIGINT相反,這個信號不能被捕獲或者忽略,而且接收過程在接收到這個信號時候不能執行任何清理,可是下面狀況爲例外:
(1)殭屍進程(zombie)進程不能被殺死,由於它們已經死了,殭屍進程在等待其父進程捕獲處理;
(2)處於阻塞狀態的進程在再次被喚醒以前不能被殺死;
(3)init進程是特殊進程,它不接收不想處理的信號,因此它能夠不接收kill信號,Linux中的ptraced init進程是例外;
(4)不間斷的睡眠進程可能不會終止(釋放資源),即便接收到SIGKILL,這是少數的須要從新啓動操做系統,用於解決臨時軟件問題的狀況之一。

在大多數操做系統關機過程當中,SIGKILL用於終止進程的最後手段,若是SIGTERM不能主動退出。
爲了更快的關機,Mac OS X 10.6(雪豹,snow leopard)把SIGKILL信號發送到被標記爲clean的應用程序,從而加快這些應用程序的關閉過程,並且估計不會帶來任何不良的影響。

shell命令kill -9對應着SIGKILL信號,該命令可能帶有不良影響,由於該命令不容許進程保存未保存的數據,一般使用更加安全的shell命令(kill 不帶參數,即SIGTERM信號)

SIGTTINSIGTTOU
後臺進程,試圖從tty讀取或者寫入時候,全部進程會收到SIGTTIN, SIGTTOU信號,一般,該信號僅由做業控制下的進程接收,守護進程沒有控制終端,所以,不會接收到這些信號。
當後臺做業要從用戶終端讀取數據時候,該做業中的全部進程會收到信號

SIGUSR1SIGUSR2
留給用戶使用,信號根據用戶定義的條件發送

SIGWINCH: signal window change
當控制終端窗口大小變化時候,SIGWINCH信號發送到進程

2.1.2 信號總結

終端Ctrl-產生信號SIGQUIT
終端Ctrl-C產生信號SIGINT
shell命令kill不帶參數產生信號SIGTERM
shell命令kill -9產生信號SIGKILL

2.2 管道

管道(pipe),一個管道基本上是內核中的一塊內存,一個由某些進程讀寫的緩衝區,使用管道的優勢是它有兩個相關聯的文件描述符,所以在兩個進程之間共享數據就像是讀寫文件同樣簡單。

import os
rfd, wfd = os.pipe()
# rfd, wfd = (3, 4) 文件描述符

基本上管道所作的是保留一個內存塊,並返回兩個文件描述符,這些描述符能夠用於從該內存塊中寫入數據和讀取數據。所以,兩個進程間通訊,進程A能夠經過wfd寫入數據,進程B能夠經過rfd讀取數據。

例如:
cat foobar | wc -l
這將運行2個進程cat foobarwc -l,標準輸出一般被更改成管道的寫入端,wc -l能夠將其標準輸入更改成管道的讀取端,用於讀取cat foobar程序輸出的數據。

這種標準輸入、標準輸出(STDINSTDOUT)到管道的變化是由shell進程控制的,

STDIN  => cat => WRITE\_END==READ\_END => wc => STDOUT

管道的基本原理和平常生活中的水管同樣,把東西從一個地方轉移到另一個地方。

還有一些要注意的,
讀會阻塞在空管道上,寫會阻塞在滿的管道上,這是由於讀空管道,沒有數據刻度,寫滿管道,沒有內存寫入空間,所以它們會等待數據的讀取或者等待內存的空閒,可使用O_NONBLOCK標誌標識管道不會阻塞

import os  
import sys  
  
  
r, w = os.pipe()  
process_id = os.fork()  
  
if process_id:  
    # Close write fd because parent not going to write  
    os.close(w)  
    r = os.fdopen(r)  
    # Read from pipe  
    msg = r.read()  
    print "msg =", msg  
    sys.exit(0)  
else:  
    # This is the child process  
    # Close read end cause child not going to read from pipe  
    os.close(r) 
    w = os.fdopen(w, 'w')  
    # Write to pipe  
    w.write("msg written by child...")  
    w.close()  
    sys.exit(0)

3、源碼解析

相關文章
相關標籤/搜索