国产成人精品三级麻豆,色综合天天综合高清网,亚洲精品夜夜夜,国产成人综合在线女婷五月99播放,色婷婷色综合激情国产日韩

當(dāng)前位置:IT培訓(xùn) > 華清遠(yuǎn)見教育科技集團(tuán) > 嵌入式學(xué)習(xí) > 講師博文 > 守護(hù)進(jìn)程解析
守護(hù)進(jìn)程解析
時(shí)間:2018-03-09作者:華清遠(yuǎn)見

一:守護(hù)進(jìn)程的簡介我們常用的進(jìn)程一般分為三類:<1>交互進(jìn)程 <2>批處理進(jìn)程<3>守護(hù)進(jìn)程。守護(hù)進(jìn)程(Daemon)是一種運(yùn)行在后臺(tái)的一種特殊的進(jìn)程,它獨(dú)立于控制終端并且周期性的執(zhí)行某種任務(wù)或等待處理某些發(fā)生的事件。守護(hù)進(jìn)程也叫精靈進(jìn)程。由于在linux中,每個(gè)系統(tǒng)與用戶進(jìn)行交流的界面成為終端,每一個(gè)從此終端開始運(yùn)行的進(jìn)程都會(huì)依附于這個(gè)終端,這個(gè)終端被稱為這些進(jìn)程的控制終端,當(dāng)控制終端被關(guān)閉的時(shí)候,相應(yīng)的進(jìn)程都會(huì)自動(dòng)關(guān)閉。但是守護(hù)進(jìn)程卻能突破這種限制,它脫離于終端并且在后臺(tái)運(yùn)行,并且它脫離終端的目的是為了避免進(jìn)程在運(yùn)行的過程中的信息在任何終端中顯示并且進(jìn)程也不會(huì)被任何終端所產(chǎn)生的終端信息所打斷。它從被執(zhí)行的時(shí)候開始運(yùn)轉(zhuǎn),知道整個(gè)系統(tǒng)關(guān)閉才退出(當(dāng)然可以認(rèn)為的殺死相應(yīng)的守護(hù)進(jìn)程)。如果想讓某個(gè)進(jìn)程不因?yàn)橛脩艋蛑袛嗷蚱渌兓绊懀敲淳捅仨毎堰@個(gè)進(jìn)程變成一個(gè)守護(hù)進(jìn)程。

二:相關(guān)概念

查看守護(hù)進(jìn)程第一行的信息。ps axj | head -1

ubuntu@farsight:/etc/profile.d$ ps axj | head -1

PPID PID PGID SID TTY TPGID STAT UID TIME

COMMAND

父進(jìn)程ID 進(jìn)程ID 進(jìn)程組ID 會(huì)話期ID 終端ID 終端進(jìn)程組ID 狀態(tài) 用戶 運(yùn)行時(shí)間

指令

1:進(jìn)程組

每運(yùn)行一個(gè)程序或是命令就會(huì)產(chǎn)生一個(gè)進(jìn)程組,而每一個(gè)進(jìn)程組有一個(gè)組長進(jìn)程。

進(jìn)程組由進(jìn)程組號(hào)(GID)標(biāo)識(shí),進(jìn)程組號(hào)(GID)為組長進(jìn)程PID,一般進(jìn)程組的第一個(gè)進(jìn)程是組長進(jìn)程。

注:進(jìn)程組中的這些進(jìn)程之間不是孤立的,他們彼此之間或者存在者父子、兄弟關(guān)系,或者在功能有相近的聯(lián)系。

那linux為什么要有進(jìn)程組呢?其實(shí)提供進(jìn)程組就是方便管理這些進(jìn)程。 進(jìn)程組的概念有很多用途,最常見的是我們在終端上向前臺(tái)執(zhí)行程序發(fā)出終止信號(hào)(Ctrl-C),同時(shí)終止整個(gè)進(jìn)程組的所有進(jìn)程。

每個(gè)進(jìn)程必定屬于一個(gè)進(jìn)程組,也只能屬于一個(gè)進(jìn)程組。

函數(shù)getpgrp可以返回調(diào)用進(jìn)程的進(jìn)程組ID
#include <unistd.h>

pid_t getpgrp(void); //得到進(jìn)程組的ID

返回值:成功則返回進(jìn)程組ID,失敗返回-1。

2:會(huì)話

一次登錄形成一個(gè)會(huì)話,一個(gè)會(huì)話可包含多個(gè)進(jìn)程組(前臺(tái)或后臺(tái)), 但只能有一個(gè)前臺(tái)進(jìn)程組,多個(gè)進(jìn)程組組成我們的會(huì)話。

setsid()可建立一個(gè)新的會(huì)話,注意進(jìn)程組的組長進(jìn)程不能調(diào)用,調(diào)用進(jìn)程是新會(huì)話的首進(jìn)程(session leader) 3:控制終端

會(huì)話的首進(jìn)程(session leader)打開一個(gè)終端之后, 該終端就成為該會(huì)話的控制終端

與控制終端建立連接的會(huì)話首進(jìn)程稱為控制進(jìn)程,一個(gè)會(huì)話只能有一個(gè)控制終端

在控制終端上產(chǎn)生的輸入和信號(hào)將發(fā)送給會(huì)話的前臺(tái)進(jìn)程組中的所有進(jìn)程

終端上的連接斷開時(shí) (比如網(wǎng)絡(luò)斷開或 Modem 斷開), 掛起信號(hào)將發(fā)送到控制進(jìn)程

守護(hù)進(jìn)程

linux是一個(gè)多用戶多任務(wù)的分時(shí)操作系統(tǒng),必須要支持多個(gè)用戶同時(shí)登陸同一個(gè)操作系統(tǒng),當(dāng)一個(gè)用戶登陸一次終端時(shí)就會(huì)產(chǎn)生一個(gè)會(huì)話。

 

每個(gè)會(huì)話有一個(gè)會(huì)話首進(jìn)程,即創(chuàng)建會(huì)話的進(jìn)程,建立與終端連接的就是這個(gè)會(huì)話首進(jìn)程,也被稱為控制進(jìn)程。
一個(gè)會(huì)話可以包括多個(gè)進(jìn)程組,這些進(jìn)程組可被分為一個(gè)前臺(tái)進(jìn)程組和一個(gè)或多個(gè)后臺(tái)進(jìn)程組。

為什么要這么分呢?前臺(tái)進(jìn)程組是指需要與終端進(jìn)行交互的進(jìn)程組(只能有一個(gè)比如有些進(jìn)程是需要完成IO操作的,那么這個(gè)進(jìn)程就會(huì)被設(shè)置為前臺(tái)進(jìn)程組.當(dāng)我們鍵入終端的中斷鍵和退出鍵時(shí),就會(huì)將信號(hào)發(fā)送到前臺(tái)進(jìn)程組中的所有進(jìn)程。而后臺(tái)進(jìn)程組是指不需要與終端進(jìn)程交互的進(jìn)程組,比如:一些進(jìn)程不需要完成IO 操作,或者一些守護(hù)進(jìn)程就會(huì) 被設(shè)置為后臺(tái)進(jìn)程組(可以有多個(gè))。

如果終端接口檢測到網(wǎng)絡(luò)已經(jīng)斷開連接,則會(huì)將掛斷信號(hào)發(fā)送給會(huì)話首進(jìn)程。

三:創(chuàng)建守護(hù)進(jìn)程

創(chuàng)建一個(gè)守護(hù)進(jìn)程的步驟如下:

<1>創(chuàng)建子進(jìn)程,父進(jìn)程退出

這是創(chuàng)建守護(hù)進(jìn)程的第一步。由于守護(hù)進(jìn)程是脫離控制終端的,因此,完成第一步后就會(huì)在Shell終端里造成一程序已經(jīng)運(yùn)行完畢的假象。之后的所有工作都在子進(jìn)程中完成,而用戶在Shell終端里則可以執(zhí)行其他命令,從而在形式上做到了與控制終端的脫離。在Linux 中父進(jìn)程先于子進(jìn)程退出會(huì)造成子進(jìn)程成為孤兒進(jìn)程,而每當(dāng)系統(tǒng)發(fā)現(xiàn)一個(gè)孤兒進(jìn)程是,就會(huì)自動(dòng)由1號(hào)進(jìn)程(init)收養(yǎng)它,這樣,原先的子進(jìn)程就會(huì)變成init進(jìn)程的子進(jìn)程。

<2>在子進(jìn)程中創(chuàng)建的新會(huì)話 [脫離控制終端]

Linux是一個(gè)多用戶多任務(wù)系統(tǒng),每個(gè)進(jìn)程都有一個(gè)進(jìn)程ID,同時(shí)每個(gè)進(jìn)程還都屬于某一個(gè)進(jìn)程組,而每個(gè)進(jìn)程組都有一個(gè)組長進(jìn)程,組長進(jìn)程的標(biāo)識(shí)ID等于進(jìn)程組的ID,且該進(jìn)程組ID不會(huì)因組長進(jìn)程的退出而受到影響。會(huì)話期是一個(gè)或多個(gè)進(jìn)程組的集合,通常,一個(gè)會(huì)話開始與用戶登錄,終止于用戶退出,在此期間該用戶運(yùn)行的所有進(jìn)程都屬于這個(gè)會(huì)話期。我們這里要用到setsid()函數(shù)。 setsid()函數(shù)的作用:創(chuàng)建一個(gè)新的會(huì)話,并且擔(dān)任該會(huì)話組的組長。具體作用包括:讓一個(gè)進(jìn)程擺脫原會(huì)話的控制,讓進(jìn)程擺脫原進(jìn)程的控制,讓進(jìn)程擺脫原控制終端的控制。

pid_t setsid(void);

(1)此進(jìn)程變成該對話期的首進(jìn)程。

(2)此進(jìn)程變成一個(gè)新進(jìn)程組的組長進(jìn)程。

(3)此進(jìn)程沒有控制終端,如果在調(diào)用setsid前,該進(jìn)程有控制終端,那么與該終端的聯(lián)系被解除。

(4)這個(gè)系統(tǒng)調(diào)用,只能由非組長進(jìn)程來調(diào)用。組長進(jìn)程不能調(diào)用。

思考:有了前邊兩個(gè)步驟,有沒有人有這樣的疑問,為什么要?jiǎng)?chuàng)建個(gè)子進(jìn)程然后父進(jìn)程退出,然后setsid()脫離當(dāng)前會(huì)話?直接就在之前的進(jìn)程中setsid()把當(dāng)前進(jìn)程脫離會(huì)話不可以么?

答案:組長進(jìn)程,一般是這個(gè)程序執(zhí)行的第一個(gè)進(jìn)程,那么我們的父進(jìn)程一般就是這組進(jìn)程的組長,而setsid()這個(gè)函數(shù)的使用,是不能由組長進(jìn)程來調(diào)用的。所以必須先創(chuàng)建一個(gè)非組長進(jìn)程來調(diào)用它。

<3>改變進(jìn)程的工作目錄到"/"

使用fork創(chuàng)建的子進(jìn)程繼承了父進(jìn)程的當(dāng)前工作目錄。

守護(hù)進(jìn)程不應(yīng)當(dāng)使用父進(jìn)程的工作目錄,應(yīng)該設(shè)置自己的工作目錄,通?梢酝ㄟ^ chdir()來完成,一般可以將其設(shè)置為根目錄。 chdir("/");

<4>重設(shè)文件掩碼 umask(0)

守護(hù)進(jìn)程從父進(jìn)程繼承來的文件創(chuàng)建方式掩碼可能會(huì)拒絕設(shè)置某些許可權(quán)限,文件權(quán)限掩碼是指屏蔽掉文件權(quán)限中的對應(yīng)位。 umask(0);

<5>關(guān)掉所有不需要的文件描述符號(hào)

如果創(chuàng)建它的進(jìn)程之前打開了某個(gè)文件,然后創(chuàng)建這個(gè)守護(hù)進(jìn)程,這樣子進(jìn)程就繼承了 fd,如果守護(hù)進(jìn)程不關(guān)閉這個(gè)fd,一個(gè)是會(huì)占用資源,二個(gè)與改變工作目錄一樣,如果這個(gè)文件是位于掛載目錄,那么就無法umount了。

這里可以關(guān)閉所有當(dāng)前系統(tǒng)的文件描述符。怎么獲取當(dāng)前進(jìn)程最大的可以打開的文件描述符個(gè)數(shù)呢?sysconf(_SC_OPEN_MAX);

<6>重新處理一下[0,1,2]==>標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出、標(biāo)準(zhǔn)出錯(cuò)。

這里需要把0,1,2重新定位一下,定位到/dev/null。這樣后邊再使用open的時(shí)候,獲得的文件描述符還可以從3開始。不然就是從0開始的,而如果我們程序中,有從0中獲取標(biāo)準(zhǔn)輸入,從1中做輸出,那么就成了對那個(gè)文件的讀寫了,這顯然是錯(cuò)誤的了。

把/dev/null看作"黑洞"。 它非常等價(jià)于一個(gè)只寫文件, 所有寫入它的內(nèi)容都會(huì)永遠(yuǎn)丟失,而嘗試從它那兒讀取內(nèi)容則什么也讀不到.。
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdlib.h>

int main(int argc, const char *argv[])

{ pid_t pid = fork();

if (pid ==-­1)

{

perror("fork()");

exit(-­1);

}

else if (0 == pid)

{

//當(dāng)前是子進(jìn)程

//1.重新設(shè)置會(huì)話

if (setsid() < 0)

{

perror("setsid()");

exit(­-1); }

//2.把工作目錄設(shè)置到根目錄

chdir("/");

//3.重新設(shè)置文件權(quán)限掩碼 umask(0);

//4.關(guān)閉所有文件描述符 int i;

for (i = 1; i < sysconf(_SC_OPEN_MAX); i++)

close(i);

//5. 特殊處理0,1,2文件描述符

open("/dev/null", O_RDWR);

open("/dev/null", O_RDWR);

open("/dev/null", O_RDWR);

}

else { /

/當(dāng)前是父進(jìn)程,直接退出

return 0;

}

return 0;

}

拓展:守護(hù)進(jìn)程創(chuàng)建之后,那么中間的調(diào)試信息不能通過屏幕輸出出來了,那么我們看不到中間的過程,怎么來調(diào)試呢?可以通過syslog來將調(diào)試信息寫到日志中。

頭文件:#include<syslog.h>

函數(shù)原型:void openlog(const char *ident,int option,int facil-ity);

函數(shù)功能:打開日志文件。

函數(shù)參數(shù):@ ident:對哪個(gè)進(jìn)程進(jìn)行日志記錄,為進(jìn)程名,如果不指定,則默認(rèn)也是進(jìn)程名。

@ option常用選項(xiàng):

LOG_CONS:如果當(dāng)前寫日志失敗了,就將信息輸出到終端控制臺(tái)。

LOG_PID:打印的每一條日志信息包含當(dāng)前進(jìn)程的PID

@ facil-ity常用選項(xiàng):

LOG_USER:打印的每一條日志信息包含當(dāng)前用戶的等級(jí)信息

函數(shù)原型:void syslog(int priority, const char *format, ...);

函數(shù)功能:向日志文件中寫日志信息。

函數(shù)參數(shù):@ format:輸出日志信息的參數(shù)列表,用法類同printf

@ priority:輸出日志的等級(jí)信息

LOG_EMERG system is unusable

LOG_ALERT action must be taken immediately

LOG_CRIT critical conditions

LOG_ERR error conditions

LOG_WARNING warning conditions

LOG_NOTICE normal, but significant, condition

LOG_INFO informational message

LOG_DEBUG debug-level message

注意:寫完的日志信息在哪里呢?一般是在/var/log目錄下,不同的發(fā)行版對應(yīng)的具體的文件不一樣,ubuntu中對應(yīng)的是/var/log/syslog文件中。

函數(shù)原型:void closelog(void);

函數(shù)功能:關(guān)閉日志文件。

一般就是在進(jìn)程啟動(dòng)的時(shí)候打開日志,在進(jìn)程結(jié)束的時(shí)候去關(guān)閉日志,這樣中間就不同的記錄就可以了,不需要每次記錄都打開關(guān)閉,甚至打開和關(guān)閉也可以不需要,系統(tǒng)在第一次調(diào)用syslog記錄日志的時(shí)候,如果發(fā)現(xiàn)日志是沒有打開的,就按照自己默認(rèn)的方式幫我們先打開日志文件,但是默認(rèn)的記錄的內(nèi)容相對簡單,如果我們自己需要控制日志中都輸出什么信息,我們最好按照自己需要的方式打開一下。


發(fā)表評(píng)論

全國咨詢電話:400-611-6270,雙休日及節(jié)假日請致電值班手機(jī):15010390966

在線咨詢: 曹老師QQ(3337544669), 徐老師QQ(1462495461), 劉老師 QQ(3108687497)

企業(yè)培訓(xùn)洽談專線:010-82600901,院校合作洽談專線:010-82600350,在線咨詢:QQ(248856300)

Copyright 2004-2018 華清遠(yuǎn)見教育科技集團(tuán) 版權(quán)所有 ,京ICP備16055225號(hào),京公海網(wǎng)安備11010802025203號(hào)

有位老師想和您聊一聊