• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            posts - 200, comments - 8, trackbacks - 0, articles - 0
                   在UNIX系統(tǒng)中,作業(yè)控制:允許在一個終端上啟動多個作業(yè)(進程組),控制哪一個作業(yè)可以存取該終端,以及哪些作業(yè)在后臺運行。一句話就是,作業(yè)控制是解決不同作業(yè)(也就是進程組)對控制終端這個資源的使用的競爭問題。作業(yè)控制作為Shell的一個特性存在,也就是說有的shell支持作業(yè)控制這個作業(yè)功能,有的不支持。linux下常用的bash是支持的作業(yè)控制功能的(通常我們使用& bg fg 等)。另外為了支持作業(yè)控制,引入了進程組,會話期,控制終端等概念,還需要內(nèi)核以一定的信號支持。

            一. 進程組、會話與終端

            (1).每個進程都屬于一個進程組。進程組是一個或多個進程的集合,通常它們與一組作業(yè)相關(guān)聯(lián),可以接受來自同一終端的各種信號。每個進程組都有唯一的進程組ID(整數(shù),也可以存放在pid_t類型中)。

                #include <unistd.h>

                pid_t getpgrp(void);

                   //返回值;調(diào)用進程的進程組ID

                每個進程組都有一個組長進程,組長進程的標識是進程組ID等于其進程ID。組長進程可以創(chuàng)建一個進程組、創(chuàng)建該組中的進程。只有某個進程中有一個進程存在,則該進程就存在,與組長進程是否終止無關(guān)。從進程組創(chuàng)建開始到其中最后一個進程離開為止的時間區(qū)間成為進程組的生存期。進程組中最后一個進程可以終止或者轉(zhuǎn)移到另一個進程組中。

                進程調(diào)用setpgid(setsid也可以)可以參加一個現(xiàn)存的組或者創(chuàng)建一個新進程組

                #include <sys/types.h>

                #include <unistd.h>

                int setpgid(pid_t pid, pid_t pgid);

                    //返回:若成功則為0,出錯為-1

                這將pid進程的進程組ID設(shè)置為pgid。如果pid是0,則使用調(diào)用者的進程ID。另外,如果pgid是0,則由pid指定的進程ID被用作為進程組ID。如果這兩個參數(shù)相等,則由pid指定的進程變成進程組組長。

                一個進程只能為它自己或它的子進程設(shè)置進程組I D。在它的子進程調(diào)用了exec后,它就不再能改變該子進程的進程組I D。

                在大多數(shù)作業(yè)控制shell中,在fork之后調(diào)用此函數(shù),使父進程設(shè)置其子進程的進程組ID,然后使子進程設(shè)置其自己的進程組ID。這些調(diào)用中有一個是冗余的,但這樣做可以保證父、子進程在進一步操作之前,子進程都進入了該進程組。否則依賴于哪一個進程先執(zhí)行,就產(chǎn)生一個競態(tài)條件。


                (2).session是一個或多個進程組的集合。

                例如,在shell中:

                $proc1 | proc2 &

                $proc3 | proc4 

            那么此時,session中就會有三個進程組存在,分別是{登陸shell(session leader)},{proc1, proc2}, {proc3, proc4}。   

                進程調(diào)用setsid函數(shù)就可建立一個新對話期。

                #include <sys/types.h>

                #include <unistd.h>

                pid_t setsid(void);

                如果調(diào)用此函數(shù)的進程不是一個進程組的組長,則此函數(shù)創(chuàng)建一個新對話期,結(jié)果為:

            (a) 此進程變成該新對話期的對話期首進程(session leader,對話期首進程是創(chuàng)建該對話期的進程)。此進程是該新對話期中的唯一進程。

            (b) 此進程成為一個新進程組的組長進程。新進程組ID是此調(diào)用進程的進程ID。

            (c) 此進程沒有控制終端。如果在調(diào)用setsid之前此進程有一個控制終端,那么這種聯(lián)系也被解除。

                如果此調(diào)用進程已經(jīng)是一個進程組的組長,則此函數(shù)返回出錯。為了保證不處于這種情況,通常先調(diào)用fork,然后使其父進程終止,而子進程則繼續(xù)。因為子進程繼承了父進程的進程組ID,而其進程ID則是新分配的,兩者不可能相等,所以這就保證了子進程不是一個進程組的組長。

                對話期和進程組有一些其他特性:

                • 一個對話期可以有一個單獨的控制終端(controlling terminal)。這通常是我們在其上登錄的終端設(shè)備(終端登錄情況)或偽終端設(shè)備(網(wǎng)絡(luò)登錄情況)。

                • 建立與控制終端連接的對話期首進程,被稱之為控制進程(controlling process)。

                • 一個對話期中的幾個進程組可被分成一個前臺進程組(foreground process group)以及一個或幾個后臺進程組(background process group)。前臺進程組接受終端輸入信號。Shell中的作業(yè)控制就是對前后臺進程組的控制,&或Ctrl+Z的進程組就是后臺進程組。

                • 如果一個對話期有一個控制終端,則它有一個前臺進程組,其他進程組則為后臺進程組。

                • 無論何時鍵入中斷鍵(常常是DELETE或Ctrl-C)或退出鍵(常常是Ctrl-\),就會造成將中斷信號或退出信號送至前臺進程組的所有進程。

                • 終端的掛斷信號送至控制進程(對話期首進程。)

                • 系統(tǒng)在登陸時將自動建立控制終端。

                如何分配一個控制終端依賴于實現(xiàn)。在open時,有幾個和控制終端相關(guān)的選項:O_NOCTTY 如果要打開的文件為終端機設(shè)備時,則不會將該終端當成進程控制終端。

                有時不管標準輸入、標準輸出是否重新定向,程序都要與控制終端交互作用。保證程序讀寫控制終端的方法是打開文件/dev/tty,在內(nèi)核中,此特殊文件代表控制終端。如果程序沒有控制終端,則打開此設(shè)備將失敗。

                注意:控制終端只有一個,通??刂平K端/dev/tty代表當前shell的控制終端,其實是一個指向?qū)嶋H終端設(shè)備的連接。實際的終端設(shè)備可能是tty1,ttyS1或者pst/1.

            (3).控制終端與終端

                首先介紹兩個抽象概念:

                tty(終端設(shè)備的統(tǒng)稱):tty一詞源于Teletypes,或者teletypewriters,原來指的是電傳打字機,是通過串行線用打印機鍵盤通過閱讀和發(fā)送信息的東西,后來這東西被鍵盤與顯示器取代,所以現(xiàn)在叫終端比較合適。終端是一種字符型設(shè)備,它有多種類型,通常使用tty來簡稱各種類型的終端設(shè)備。

                pty(偽終端,虛擬終端):遠程telnet到主機或使用xterm時不也需要一個終端交互。

                在Linux系統(tǒng)的設(shè)備特殊文件目錄/dev/下,終端特殊設(shè)備文件一般有以下幾種:

              1、串行端口終端(/dev/ttySn) 串行端口終端(Serial Port Terminal)是使用計算機串行端口連接的終端設(shè)備。計算機把每個串行端口都看作是一個字符設(shè)備。有段時間這些串行端口設(shè)備通常被稱為終端設(shè)備,因為那時它的最大用途就是用來連接終端。

               2、偽終端(/dev/pty/) 偽終端(Pseudo Terminal)是成對的邏輯終端設(shè)備(即master和slave設(shè)備, 對master的操作會反映到slave上)。例如/dev/ptyp3和/dev/ttyp3(或者在設(shè)備文件系統(tǒng)中分別是/dev/pty /m3和/dev/pty/s3)。它們與實際物理設(shè)備并不直接相關(guān)。如果一個程序把ptyp3(master設(shè)備)看作是一個串行端口設(shè)備,則它對該端口的讀/ 寫操作會反映在該邏輯終端設(shè)備對應(yīng)的另一個ttyp3(slave設(shè)備)上面。而ttyp3則是另一個程序用于讀寫操作的邏輯設(shè)備。telnet主機A就是通過“偽終端”與主機A的登錄程序進行通信。

                3、控制終端(/dev/tty) 如果當前進程有控制終端(Controlling Terminal)的話,那么/dev/tty就是當前進程的控制終端的設(shè)備特殊文件??梢允褂妹?#8221;ps –ax”來查看進程與哪個控制終端相連。對于你登錄的shell,/dev/tty是你當前的控制終端,設(shè)備號是(5,0)。使用命令”tty”可以查看它具體對應(yīng)哪個實際終端設(shè)備。/dev/tty有些類似于到實際所使用終端設(shè)備的一個聯(lián)接。在當前的控制終端的讀寫都會寫到當前的終端設(shè)備中,例如echo "hello" > /dev/tty ,都會直接顯示在當前的終端中。而cat </dev/tty會從當前終端讀取輸入(行緩沖)并輸出出來。

                4、控制臺終端(/dev/ttyn, /dev/console) 在Linux 系統(tǒng)中,計算機顯示器通常被稱為控制臺終端(Console)。它仿真了類型為Linux的一種終端(TERM=Linux),并且有一些設(shè)備特殊文件與之相關(guān)聯(lián):tty0、tty1、tty2 等。當你在控制臺上登錄時,使用的是tty1。使用Alt+[F1—F6]組合鍵時,我們就可以切換到tty2、tty3等上面去。tty1–tty6等稱為虛擬終端,而tty0則是當前所使用虛擬終端的一個別名,系統(tǒng)所產(chǎn)生的信息會發(fā)送到該終端上(這時也叫控制臺終端)。因此不管當前正在使用哪個虛擬終端,系統(tǒng)信息都會發(fā)送到控制臺終端上。/dev/console即控制臺,是與操作系統(tǒng)交互的設(shè)備,系統(tǒng)將一些信息直接輸出到控制臺上。目前只有在單用戶模式下,才允許用戶登錄控制臺。

                5、虛擬終端(/dev/pts/n)在Xwindows模式下的偽終端.如我在Kubuntu下用konsole,就是用的虛擬終端,用tty命令可看到/dev/pts/1。

                6、其它類型Linux系統(tǒng)中還針對很多不同的字符設(shè)備存在有很多其它種類的終端設(shè)備特殊文件。例如針對ISDN設(shè)備的/dev/ttyIn終端設(shè)備等。

                

            (4).幾個常用的終端相關(guān)命令

            (a). 在ubuntu等發(fā)行版本中,圖形界面下Ctrl+Alt+F1-F6是打開tty1-6的終端()。在tty1-6這些終端下Alt1-6是切換終端,Alt+F7進入圖形界面。

             

            (b). 可以通過ps -t的方式查看其他終端進程(這些終端在初始進入時候?qū)儆趃etty狀態(tài),由于tty1終端尚未登錄所以運行g(shù)etty。而且沒有其他進程使用tty1終端):

                $ps -t tty1

                PID TTY          TIME CMD

                1524 tty1     00:00:00 getty

             

            (c). 可以使用shell的tty命令來識別現(xiàn)在使用的終端:

                $ tty

                /dev/pts/0

             

            (d). stty - set tty, change and print terminal line settings

            $stty -a    命令用于檢查和修改當前控制終端的通信參數(shù)。UNIX系統(tǒng)為鍵盤的輸入和終端的輸出提供了重要的控制手段,可以通過stty命令對特定終端或通信線路設(shè)置選項.

            $stty tostop        #[-]tostop  STOP嘗試向終端寫入數(shù)據(jù)的后臺任務(wù)。(SIGTTOU)

            $echo "hello world" &   #試圖輸出的進程會被終止

            [1] 3063

            $ fg

            echo "hello world"

            hello world

             

            $ stty -tostop

            $ echo "hello world" &

            [1] 3065

            hello world     #不STOP結(jié)果直接被輸出出來。

            $ jobs

            [1]+  完成                 echo "hello world"

            所有選項,-option_name是關(guān)閉,option_name是打開。對于控制終端的設(shè)置也是管理中重要的工作之一。

             

            (4).需要有一種方法來通知內(nèi)核哪一個進程組是前臺進程組,這樣,終端設(shè)備驅(qū)動程序就能了解將終端輸入和終端產(chǎn)生的信號送到何處。

                #include <termios.h>

                #include <unistd.h>

                int tcgetattr(int fd, struct termios *termios_p);   //成功則返回與終端文件描述符fd相關(guān)聯(lián)的前臺進程的組ID,出錯則返回-1。

                int tcsetattr(int fd, int optional_actions, const struct termios *termios_p);   //成功則返回0,出錯則返回-1

                //struct termios定義一和終端相關(guān)的標識字段,例忽略BREAK鍵,忽略校驗等等。

                大多數(shù)應(yīng)用程序不直接調(diào)用這兩個函數(shù),它們通常由作業(yè)控制shell調(diào)用。

            ---
            ---
            ---
            ---------------------------
            ---
            ---
            ---
            ---------------------------
            ---
            ---
            ---
            ---------------------------
            ---
            ---
            ---
            ---------------------------
            二. 作業(yè)控制

            (1).允許在一個終端上起動多個作業(yè)(進程組),控制哪一個作業(yè)可以存取該終端,以及哪些作業(yè)在后臺運行。作業(yè)控制要求三種形式的支持:

            (a).支持作業(yè)控制的shell。

            (b).內(nèi)核中的終端驅(qū)動程序必須支持作業(yè)控制。

            (c).必須提供對某些作業(yè)控制信號的支持。

            三個特殊字符可使終端驅(qū)動程序產(chǎn)生信號,并將它們送至前臺進程組,它們是:

            • 中斷字符(一般采用DELETE或Ctrl-C)產(chǎn)生SIGINT。

            • 退出字符(一般采用Ctrl-\)產(chǎn)生SIGQUIT。

            • 掛起字符(一般采用Ctrl-Z)產(chǎn)生SIGTSTP。

            (2).不支持作業(yè)控制的Shell

                對于不支持作業(yè)控制的Shell,例如bsh,它的命令和它自身的進程處于同一個會話和前臺進程組。在后臺執(zhí)行的命令(&)和管道命令的進程依然和Shell是同一個進程組。

                如果一個后臺進程試圖取走終端,例如cat > temp &。在有作業(yè)控制時,后臺作業(yè)被放在后臺進程組中。如果后臺作業(yè)試土讀控制終端,則會產(chǎn)生信號SIGTTIN。在沒有作業(yè)控制時,其處理方法是如果該進程自己沒有重定向標準輸入,則Shell會自動將標準輸入重定向到/dev/null。讀/dev/null則會產(chǎn)生一個EOF讓cat讀到文件末尾,正常結(jié)束。另外,管道執(zhí)行的結(jié)構(gòu)圖如下:

            <圖>

            (3).支持作業(yè)控制的Shell

            $ ps -o pid -o ppid -o sid -o pgid -o command

              PID  PPID   SID  PGID COMMAND

             2074  2068  2074  2074 /bin/bash

             2580  2074  2074  2580 ps -o pid -o ppid -o sid -o pgid -o command

            可以看出它們有不同的PGID。對于管道命令,他們屬于同一個進程組:

            $ ps -o pid -o ppid -o sid -o pgid -o command | cat

              PID  PPID   SID  PGID COMMAND

             2074  2068  2074  2074 /bin/bash

             2584  2074  2074  2584 ps -o pid -o ppid -o sid -o pgid -o command

             2585  2074  2074  2584 cat

            (4).SIGHUP信號

                SIGHUP會在以下3種情況下被發(fā)送給相應(yīng)的進程:

            1、終端關(guān)閉時,該信號被發(fā)送到session首進程以及作為job提交的進程(即用& 符號提交的進程)

            2、session首進程退出時,該信號被發(fā)送到該session中的前臺進程組中的每一個進程

            3、若父進程退出導致進程組成為孤兒進程組,且該進程組中有進程處于停止狀態(tài)(收到SIGTSTP信號),SIGHUP會被發(fā)送到該進程組中的每一個進程。

                系統(tǒng)對SIGHUP信號的默認處理是終止收到該信號的進程。所以若程序中沒有捕捉該信號,當收到該信號時,進程就會退出。

                If a controlling process exits, the system revokes further access to the controlling terminal and sends a SIGHUP signal to the foreground process group. If a process such as a job-control shell exits, each process group that it created will become an orphaned process group。

            (5).bash作業(yè)控制命令

            (a). nohup:使用nohup讓程序永遠后臺運行

               由于很多程序不是守護進程,我們又想讓它在后臺運行,不受SIGHUP信號影響(例如shell退出或者終端連接斷開),那么使用nohup命令。

                $nohup sleep 100 &

                $appending output to nohup.out  #無論是否將命令重定向輸出輸出終端,輸出都將附加到當前目錄的nohup文件中。

                $ps -t pts/0

                #可以看到sleep 100進程終端為pts/0

                $exit

               然后打開另一終端:

               $ tty

                /dev/pts/1

                $ ps -ef | grep sleep | grep -v grep

                luffy     4171     1  0 18:12 ?        00:00:00 sleep 100

                #100秒后再次查詢,結(jié)果為空。說明進程正常退出   

            (b). 作業(yè)號%n:支持作業(yè)控制的Shell可以識別%+作業(yè)號的作業(yè)進程

            例如:

            $ sleep 10&

            [1] 4294

            $ %1        #bring %1 to front,same as fg %1

            sleep 10

            (c).$fg 則將第一個作業(yè)放到前臺。fg %n

            (d).bg 將一個在后臺暫停的命令,變成繼續(xù)執(zhí)行 如果后臺中有多個命令,可以用bg %jobnumber將選中的命令調(diào)出,%jobnumber是通過jobs命令查到的后臺正在執(zhí)行的命令的序號(不是pid)。

            (e).jobs

            (f). ctrl+z or &

             

            (6).Linux讓進程在后臺執(zhí)行

            (a). nohup命令:略

            (b). setsid命令. 如果我們的進程不屬于接受HUP 信號的終端的子進程,那么自然也就不會受到HUP 信號的影響了。setsid 就能幫助我們做到這一點。系統(tǒng)調(diào)用setsid()請見前面。

            $setsid ping www.baidu.com

            $ PING www.a.shifen.com (119.75.218.70) 56(84) bytes of data.

            64 bytes from 119.75.218.70: icmp_req=1 ttl=54 time=1.88 ms

            ......

            ^C

            64 bytes from 119.75.218.70: icmp_req=3 ttl=54 time=1.65 ms

            64 bytes from 119.75.218.70: icmp_req=4 ttl=54 time=1.92 ms

            ......

            輸出信息會不斷出現(xiàn)在這個終端,由于這個進程已經(jīng)不是這個Shell的會話了,所以Ctrl+C不能終止這個進程。就算關(guān)閉整個終端,程序也會繼續(xù)執(zhí)行。

            在另一個終端將它終止 :

            $ ps -e -o pid -o sid -o pgid -o command | grep ping | grep -v grep

             4474  4474  4474 ping www.baidu.com

            #可以看出sid=pid.由于是

            $ kill -SIGKILL 4396

            $ ps -ef | grep ping |grep -v grep

            進程被kill掉。

            (c).(&)

            subshell:一個或多個命令包含在()里執(zhí)行就能讓他們在子shell中執(zhí)行。所以讓在子shell中執(zhí)行的作業(yè)用jobs看不到,自然也不會接收任何hup信號。例如:

            $(ping www.baidu.com &)

            (d).disown

            對于已經(jīng)提交出去的命令,使用作業(yè)調(diào)度disown來達到目的:

            用disown -h jobspec 來使某個作業(yè)忽略HUP信號。

            用disown -ah 來使所有的作業(yè)都忽略HUP信號。

            用disown -rh 來使正在運行的作業(yè)忽略HUP信號。

            # cp -r testLargeFile largeFile &

            [1] 4825

            # jobs

            [1]+  Running                 cp -i -r testLargeFile largeFile &

            # disown -h %1

            # ps -ef |grep largeFile

            root      4825   968  1 09:46 pts/4    00:00:00 cp -i -r testLargeFile largeFile

            root      4853   968  0 09:46 pts/4    00:00:00 grep largeFile

            # logout  

            對于正在運行,沒有加&放到后臺運行的程序可以先ctrl+Z停止進程,然后用bg %n讓這個作業(yè)繼續(xù)執(zhí)行。再用disown忽略hup信號。

            (e). screen終端模擬器,功能強大這里只簡單介紹。

            沒有啟動screen的進程樹 :

            $ ping www.baidu.com >~/temp.output &

            [1] 4962

            $ pstree -H 4962        #讓指定的進程高亮顯示

            init─┬─/usr/bin/termin─┬─bash

                 │                ├─bash─┬─ping

            ......

            在使用了screen的進程樹

            # screen -r Urumchi

            # ping www.ibm.com &

            [1] 9488

            # pstree -H 9488

            init-+-/usr/bin/termin-+-bash

                 |                 |-bash-+-ping

                 |                 |      `-screen---screen-+-bash

             

            Reference:

            APUE

            man

            Stty使用一技    http://fanqiang.chinaunix.net/a1/b4/20020606/060200245.html

            Linux中的終端、控制臺、tty、pty等概念    http://news.newhua.com/news1program_language/2010/623/10623141048745773199BCF0CFH6AKB9930IGCFKHBH4IBE65IDFI07F.html

            IBM文庫-Linux 技巧:讓進程在后臺可靠運行的幾種方法http://www.ibm.com/developerworks/




            久久久久一区二区三区| 国产偷久久久精品专区| 国产成人香蕉久久久久| 亚洲国产成人久久综合区| 久久精品国产亚洲AV影院| 国产精品久久亚洲不卡动漫| 久久强奷乱码老熟女网站| 久久综合亚洲欧美成人| 久久精品国产国产精品四凭| 久久久久久久久久久久中文字幕| 久久国产精品视频| 久久香综合精品久久伊人| 亚洲国产综合久久天堂| 99久久免费只有精品国产| 亚洲精品tv久久久久久久久| 精品国产乱码久久久久久浪潮| 男女久久久国产一区二区三区| 怡红院日本一道日本久久 | 久久www免费人成看国产片| 欧美精品乱码99久久蜜桃| 亚洲国产精品久久66| 久久人人爽爽爽人久久久| 久久妇女高潮几次MBA| 久久久久亚洲AV无码专区桃色| 99久久精品日本一区二区免费| 久久这里的只有是精品23| 欧美伊人久久大香线蕉综合69| 国产成人无码精品久久久免费| 国产成人无码久久久精品一| 少妇久久久久久被弄高潮| 久久AV无码精品人妻糸列| 免费久久人人爽人人爽av| 天天综合久久一二三区| 午夜精品久久久久久影视777| 国产精品狼人久久久久影院| 中文字幕一区二区三区久久网站 | 色噜噜狠狠先锋影音久久| 久久青青草原国产精品免费| 亚洲综合久久综合激情久久| 久久精品免费一区二区三区| 国产亚州精品女人久久久久久 |