併發程式設計(四)

2022-07-03 13:24:11 字數 4128 閱讀 6748

上篇部落格介紹了程序的建立,程序的相關屬性以及三種特殊程序:殭屍程序,孤兒程序和守護程序.

守護程序是乙個在後台執行並且不受任何終端控制的程序,用於執行特定的系統任務.很多守護程序在系統引導的時候啟動,並且一直執行直到系統關閉.另一些只在需要的時候才啟動,完成任務後就自動結束.

本篇部落格詳細介紹守護程序的產生原因以及作用.(因為我覺得守護程序對作業系統的正常執行還蠻重要的)

守護程序是乙個在後台執行並且不受任何終端控制的程序. unix 作業系統有很多典型的守護程序,他們在後台執行,執行不同的管理任務.

使用者使守護程序獨立於所有終端是因為,在守護程序從乙個終端啟動的情況下,這同乙個終端可能被其他的使用者使用.例如,使用者從乙個終端啟動守護程序後退出,然後另乙個人也登陸到這個終端.使用者不希望後者在使用該終端的過程中,接收到守護程序的任何錯誤資訊.同樣,由終端鍵入的任何訊號(例如中斷訊號)也不應該影響先前在該終端啟動的任何守護程序的執行.雖然讓伺服器後台執行很容易(只要shell 命令列以&結尾),但使用者還應該做些工作,讓程式本身能夠自動進入後台,且不依賴於任何終端.

守護程序沒有控制終端,因此當某些情況發生時,不管是一般的報告性資訊,還是由管理員處理的緊急資訊,都需要以某種方式輸出. syslog 函式就是輸出這些資訊的標準方法,它把資訊傳送給 syslogd 守護程序.

在不同 unix環境下,守護程序的具體變成細節並不一致.但所幸的是,守護程序的程式設計原則都一樣,區別僅在於具體的實現細節不同,這個原則就是要滿足守護程序的特性.程式設計規則如下:

為避免掛起控制終端,要將守護程序放入後台執行,其方法是在父程序中呼叫 fork 使父程序終止,讓子程序在後台執行,使得程式在 shell 終端裡造成乙個已經執行完畢的假象.之後所有的工作都在子程序中完成,而使用者在 shell 終端裡則可以執行其他命令,從而使得程式以殭屍程序執行,在形式上做到了與控制終端的隔離.具體就是 fork 產生子程序後,呼叫 exit 使父程序終止.

登陸回話可以包含多個程序組,這些程序組共享乙個控制終端,這個控制終端通常是建立程序的登陸終端,控制終端,登陸回話和程序組通常都是從父程序繼承下來的.目的就是要脫離這些繼承的東西,不受它們的影響.

這就要使用 setsid 函式使程序成為會話組長.

setsid

setsid 命令 子程序從父程序繼承了: session id, 程序組 id 合開啟的終端.子程序如果要脫離這些,**中可通過呼叫 setsid 來實現.而命令列或指令碼中可以通過命令setsid 來實現. setsid 幫助乙個程序脫離從父程序繼承而來的已開啟的終端,會話和程序組.

需要說明的是,當程序是會話組長時, setsid 呼叫會失敗,大第一點已經保證程序不是會話組長.setsid 呼叫成功後,程序會成為新的會話組長和新的程序組長,並與原來的登陸會話和程序組脫離,由於會話過程對控制終端的獨占性,程序同時與控制終端脫離.

具體操作就是:

成為新會話的首程序;

成為乙個新程序組的首程序;

沒有控制終端.

現在程序已經成為無終端的會話組長,但它可以重新申請開啟乙個控制終端.可以通過是程序不再成為會話組長來禁止程序重新開啟控制終端.

程序從建立它的父程序那裡繼承了開啟的檔案描述符.如果不關閉,會造成資源浪給,造成程序所在地檔案系統無法卸下以及產生無法預料的錯誤.一般來說,必要的是關閉0,1,2三個檔案描述符,即標準輸入,標準輸出,標準錯誤.因為一般希望守護程序自己有一套資訊輸出,輸入的體系,而不是把所有的東西都傳送到終端螢幕上.所以需要呼叫 fclose 來關閉檔案描述符.

將當前工作目錄更改為根目錄,從父程序繼承過來的當前工作目錄可能在乙個裝配的檔案系統中.因為守護程序通常在系統引導之前是一直存在的,所以如果守護程序的當前工作目錄在乙個裝配檔案系統中,那麼該檔案系統就不能被拆卸.

另外,某些守護程序可能會把當前工作目錄更改到某個指定位置,在此位置做它們的工作.例如,行式印表機守護程序常常將工作目錄更改到 spool 目錄上.可以呼叫 chdir 更改工作目錄.

檔案建立掩碼是指遮蔽掉檔案建立時的對應為.由於使用 fork 後函式新建的子程序繼承了父程序的檔案建立掩碼,這就給該子程序使用檔案帶來了諸多麻煩.因此,把檔案建立掩碼設定為0,可以大大增強該守護程序的靈活性.設定檔案建立掩碼的函式是 umask, 通常的使用方法為umask(0).

處理 sigchld 訊號並不是必需的.但是對於某些守護程序,特別是伺服器程序往往在請求到來時生產子程序出來請求.如果父程序不等待子程序結束,子程序將成為殭屍程序而占用系統資源.如果父程序等待子程序結束,將增加父程序的負擔,影響伺服器程序的併發效能.在系統下可以簡單的將 sigchld 訊號的操作設為 sig-ign:

signal(sigchld,sig_ign)

這樣,核心在子程序結束後不會產生殭屍程序,這一點與 bsd4不同,雜 ibsd4下必須顯式等待子程序結束後才能釋放殭屍程序.

import time

import os

import sys

def initdaemon(stdoutfd, stderrfd=none, basepath=none):

'''初始化為 daemon 程序

'''basepath = '/' if basepath is none else basepath

curtimestr = time.strftime('%y-%m-%d %h:%m:%s')

try:

stdoutfd.write('start on %s, ' % curtimestr)

stdoutfd.flush()

except:

raise

try:

if os.fork() > 0:

os._exit(0)

except oserror:

raise oserror('fork error')

os.chdir(basepath)

os.setsid()

sys.stdout = stdoutfd

sys.stderr = stdoutfd if stderrfd is none else stderrfd

sys.stdin = open('/dev/nu,,', 'r')

try:

if os.fork() > 0:

os._exit(0)

except oserror:

raise oserror('fork 2 error')

pid = int(os.getpid())

stdoutfd.write('pid=%s\n' % pid)

stdoutfd.flush()

return

獨立執行的守護程序有 init 指令碼負責管理,所有獨立執行的守護程序的指令碼在/etc/rc和/etc/init.d 目錄下.系統服務都是獨立執行的守護程序包括 syslogd 和 cron 等.伺服器監聽乙個特定的埠上等待客戶端的連線.如果客戶端產生乙個連線請求,守護程序就建立乙個子伺服器響應這個連線,而主伺服器繼續監聽.以保持多個子伺服器池等待下乙個客戶端請求連線.

從守護程序的概念可以看出,系統所執行的每一種服務,都必須執行乙個監聽某個埠連線所發生的守護程序,這通常意味著資源浪費.為了解決這個問題, linux 引進了'網路守護程序服務程式'的概念. centos6.4使用的網路守護程序是 xinted(extendedinternet services daemon).

上圖是 ubuntu18.04使用的網路守護程序服務程式, xinted 能夠同時監聽多個指定的埠,在接受使用者請求時,它能夠根據使用者請求的埠不同,啟動不同的網路服務程序來處理這些使用者請求.可以把 xinted 看做乙個管理啟動服務的管理伺服器,它決定把乙個客戶請求交給那個程式處理,然後啟動相應的守護程序.

按照服務型別分為如下幾個:

對於乙個作業系統來說,為了執行不同的管理任務,需要守護程序來協助管理.對於守護程序最重要的來說是需要在後台執行.其次,守護程序必須與其執行前的環境隔離開來.這些環境包括未關閉的檔案描述符,控制終端,會話和程序組,工作目錄以及檔案建立掩碼等.這些環境通常是守護程序從執行它的父程序(特別是 shell)繼承下來的.最後守護程序的啟動方式有其特殊之處.它可以在 linux 系統啟動時從啟動指令碼/etc/rc. d中啟動,也可以由作業控制程序 crond 啟動,還可以由使用者終端(通常是 shell)執行.

除這幾點之外,守護程序與普通程序基本上沒什麼區別.因此,編寫守護程序實際上是把乙個普通程序按照上述的守護程序的特性改造成為守護程序.

併發程式設計(四)

在併發佇列上jdk提供了兩套實現,乙個是以concurrentlinkedqueue為代表的高效能佇列,乙個是以blockingqueue介面為代表的阻塞佇列,無論哪種都繼承自queue。1 concurrentlinkedqueue 是乙個適用於高併發場景下的佇列,通過無鎖的方式,實現了高併發狀態...

併發程式設計 四

是指乙個執行緒a呼叫了物件o的wait 方法進入等待狀態,而另乙個執行緒b呼叫了物件o的notify 或者notifyall 方法,執行緒a收到通知後從物件o的wait 方法返回,進而執行後續操作。上述兩個執行緒通過物件o來完成互動,而物件上的wait 和notify notifyall 的關係就如...

併發程式設計框架篇(四)

一 disruptor框架 1 disruptor礦機在jvm平台上,其核心是乙個業務邏輯處理器,它能夠在乙個執行緒裡每秒處理6百萬訂單 業務邏輯處理器完全是在記憶體中,使用事件源驅動方式。業務邏輯處理器的核心是disruptor。2 disruptor它是乙個開源的併發框架,並獲得2011 duk...