• <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>

            Prayer

            在一般中尋求卓越
            posts - 1256, comments - 190, trackbacks - 0, articles - 0
              C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

            fork, wait, system

            Posted on 2009-09-28 13:53 Prayer 閱讀(1232) 評論(0)  編輯 收藏 引用 所屬分類: LINUX/UNIX/AIX

            fork,vfork


            #include <unistd.h>;
            #include <sys/types.h>;

            main ()
            {
                    pid_t pid;
                    pid=fork();

                    if (pid < 0)
                            printf("error in fork!");
                    else if (pid == 0)
                            printf("i am the child process, my process id is %d\n",getpid());
                    else
                            printf("i am the parent process, my process id is %d\n",getpid());
            }
            要搞清楚fork的執(zhí)行過程,就必須先講清楚操作系統(tǒng)中的“進(jìn)程(process)”概念。一個進(jìn)程,主要包含三個元素:

            o. 一個可以執(zhí)行的程序;
            o. 和該進(jìn)程相關(guān)聯(lián)的全部數(shù)據(jù)(包括變量,內(nèi)存空間,緩沖區(qū)等等);
            o. 程序的執(zhí)行上下文(execution context)。

            不妨簡單理解為,一個進(jìn)程表示的,就是一個可執(zhí)行程序的一次執(zhí)行過程中的一個狀態(tài)。操作系統(tǒng)對進(jìn)程的管理,典型的情況,是通過進(jìn)程表完成的。進(jìn)程表中的每 一個表項,記錄的是當(dāng)前操作系統(tǒng)中一個進(jìn)程的情況。對于單 CPU的情況而言,每一特定時刻只有一個進(jìn)程占用 CPU,但是系統(tǒng)中可能同時存在多個活動的(等待執(zhí)行或繼續(xù)執(zhí)行的)進(jìn)程。

            一個稱為“程序計數(shù)器(program counter, pc)”的寄存器,指出當(dāng)前占用 CPU的進(jìn)程要執(zhí)行的下一條指令的位置。

            當(dāng)分給某個進(jìn)程的 CPU時間已經(jīng)用完,操作系統(tǒng)將該進(jìn)程相關(guān)的寄存器的值,保存到該進(jìn)程在進(jìn)程表中對應(yīng)的表項里面;把將要接替這個進(jìn)程占用 CPU的那個進(jìn)程的上下文,從進(jìn)程表中讀出,并更新相應(yīng)的寄存器(這個過程稱為“上下文交換(process context switch)”,實際的上下文交換需要涉及到更多的數(shù)據(jù),那和fork無關(guān),不再多說,主要要記住程序寄存器pc指出程序當(dāng)前已經(jīng)執(zhí)行到哪里,是進(jìn)程上 下文的重要內(nèi)容,換出 CPU的進(jìn)程要保存這個寄存器的值,換入CPU的進(jìn)程,也要根據(jù)進(jìn)程表中保存的本進(jìn)程執(zhí)行上下文信息,更新這個寄存器)。

            好了,有這些概念打底,可以說fork了。當(dāng)你的程序執(zhí)行到下面的語句:
            pid=fork();
            操作系統(tǒng)創(chuàng)建一個新的進(jìn)程(子進(jìn)程),并且在進(jìn)程表中相應(yīng)為它建立一個新的表項。新進(jìn)程和原有進(jìn)程的可執(zhí)行程序是同一個程序;上下文和數(shù)據(jù),絕大部分就是 原進(jìn)程(父進(jìn)程)的拷貝,但它們是兩個相互獨立的進(jìn)程!此時程序寄存器pc,在父、子進(jìn)程的上下文中都聲稱,這個進(jìn)程目前執(zhí)行到fork調(diào)用即將返回(此 時子進(jìn)程不占有CPU,子進(jìn)程的pc不是真正保存在寄存器中,而是作為進(jìn)程上下文保存在進(jìn)程表中的對應(yīng)表項內(nèi))。問題是怎么返回,在父子進(jìn)程中就分道揚 鑣。

            父進(jìn)程繼續(xù)執(zhí)行,操作系統(tǒng)對fork的實現(xiàn),使這個調(diào)用在父進(jìn)程中返回剛剛創(chuàng)建的子進(jìn)程的pid(一個正整數(shù)),所以下面的if語句中pid<0, pid==0的兩個分支都不會執(zhí)行。所以輸出i am the parent process...

            子進(jìn)程在之后的某個時候得到調(diào)度,它的上下文被換入,占據(jù) CPU,操作系統(tǒng)對fork的實現(xiàn),使得子進(jìn)程中fork調(diào)用返回0。所以在這個進(jìn)程(注意這不是父進(jìn)程了哦,雖然是同一個程序,但是這是同一個程序的另 外一次執(zhí)行,在操作系統(tǒng)中這次執(zhí)行是由另外一個進(jìn)程表示的,從執(zhí)行的角度說和父進(jìn)程相互獨立)中pid=0。這個進(jìn)程繼續(xù)執(zhí)行的過程中,if語句中 pid<0不滿足,但是pid==0是true。所以輸出i am the child process...

            我想你比較困惑的就是,為什么看上去程序中互斥的兩個分支都被執(zhí)行了。在一個程序的一次執(zhí)行中,這當(dāng)然是不可能的;但是你看到的兩行輸出是來自兩個進(jìn)程,這兩個進(jìn)程來自同一個程序的兩次執(zhí)行。


            #include <sys/types.h>
            #include <unistd.h>
            #include <stdio.h>
            #include <stdlib.h>
            globa=6;
            int main(void)
            {
             var=88;
             pid_t result;
             result = fork();
            //result = vfork();
             if(result == -1)
             {
              perror("fork");
              exit;
             }
             else if(result == 0)
             {
              globa++;
              var++;
              printf("The return value is %d\n In child process!!\n My PID is %d\n",result,getpid());
             }
             else
             {
              printf("The return value is %d\n In father process!!\n My PID is %d\n",result,getpid());
             }
             printf("PID=%d,globa=%d,var=%d",getpid(),globa,var);
            }
            程序運行結(jié)果如下:
            (fork()運行結(jié)果)
            The return value is 0
             In child process!!
             My PID is 3736
            PID=3736,globa=7,var=89
            The return value is 3736
             In father process!!
             My PID is 3735
            PID=3735,globa=6,var=88
             
            (vfork()運行結(jié)果)
            The return value is 0
             In child process!!
             My PID is 3736
            PID=3736,globa=7,var=89
            The return value is 3736
             In father process!!
             My PID is 3735
            PID=3735,globa=7,var=89
             
            分析:首先分析fork與vfork函數(shù)的運行機(jī)制,拿fork為例,fork()并不是進(jìn)程切換,而是復(fù)制一個當(dāng)前進(jìn)程。當(dāng)使用pid= fork()時,其實是創(chuàng)建了兩個進(jìn)程,這兩個進(jìn)程有著相同的內(nèi)容,例如變量的值,空間配,特別是正在執(zhí)行的語句等等都相同,但這些內(nèi)容卻在兩個獨立的內(nèi) 存空間中。因此當(dāng)執(zhí)行上述代碼時,便相當(dāng)于同一段代碼在兩個進(jìn)程中執(zhí)行,所有就出現(xiàn)了兩個結(jié)果,一個是子進(jìn)程的信息,一個是父進(jìn)程的信息。再看globa 和var這兩個變量,由于是兩個獨立的進(jìn)程,因此當(dāng)各自執(zhí)行代碼時,變量也不會互相受到影響,所以在子進(jìn)程中的globa和var均發(fā)生了變化,而在父進(jìn) 程中卻沒有變化。
                 其次分析一下,fork()和vfork()的區(qū)別:vfork采用寫時拷貝技術(shù)(write-on-copy),父進(jìn)程與子進(jìn)程享用同一個內(nèi)存空間,因 此,程序中的變量其實也就是父子進(jìn)程的公共變量,所以,當(dāng)其中一個進(jìn)程中的變量值發(fā)生改變時,另一個進(jìn)程中的變量值肯定也跟著發(fā)生變化,另外,兩個函數(shù)的 區(qū)別還在于vfork用于創(chuàng)建一個新進(jìn)程,而該新進(jìn)程的目的是exec一個新進(jìn)程,vfork和fork一樣都創(chuàng)建一個子進(jìn)程,但是它并不將父進(jìn)程的地址 空間完全復(fù)制到子進(jìn)程中,因為子進(jìn)程會立即調(diào)用exec,于是也就不會存放該地址空間。不過在子進(jìn)程中調(diào)用exec或exit之前,他在父進(jìn)程的空間中運 行。vfork保證子進(jìn)程先運行,在她調(diào)用exec exit之后父進(jìn)程才可能被調(diào)度運行。如果在調(diào)用這兩個函數(shù)之前子進(jìn)程依賴于父進(jìn)程的進(jìn)一步動作,則會導(dǎo)致死鎖。 用fork函數(shù)創(chuàng)建子進(jìn)程后,子進(jìn)程往往要調(diào)用一種exec函數(shù)以執(zhí)行另一個程序,當(dāng)進(jìn)程調(diào)用一種exec函數(shù)時,該進(jìn)程完全由新程序代換,而新程序則從 其main函數(shù)開始執(zhí)行,因為調(diào)用exec并不創(chuàng)建新進(jìn)程,所以前后的進(jìn)程id 并未改變,exec只是用另一個新程序替換了當(dāng)前進(jìn)程的正文,數(shù)據(jù),堆和棧段。


            wait(等待子進(jìn)程中斷或結(jié)束)
            相關(guān)函數(shù) waitpid,fork
            表頭文件
            #include
            #include
            定義函數(shù) pid_t wait (int * status);
            函數(shù)說明
            wait()會暫時停止目前進(jìn)程的執(zhí)行,直到有信號來到或子進(jìn)程結(jié)
            束。如果在調(diào)用wait()時子進(jìn)程已經(jīng)結(jié)束,則wait()會立即返
            回子進(jìn)程結(jié)束狀態(tài)值。子進(jìn)程的結(jié)束狀態(tài)值會由參數(shù)status 返回,
            而子進(jìn)程的進(jìn)程識別碼也會一快返回。如果不在意結(jié)束狀態(tài)值,則
            參數(shù)status 可以設(shè)成NULL。子進(jìn)程的結(jié)束狀態(tài)值請參考waitpid()。
            返回值
            如果執(zhí)行成功則返回子進(jìn)程識別碼(PID),如果有錯誤發(fā)生則返回
            -1。失敗原因存于errno 中。
            附加說明
            范例
            #include
            #include
            #include
            #include
            main()
            {
            pid_t pid;
            int status,i;
            if(fork()= =0){
            printf(“This is the child process .pid =%d\n”,getpid());
            exit(5);
            }else{
            sleep(1);
            printf(“This is the parent process ,wait for child...\n”;
            pid=wait(&status);
            i=WEXITSTATUS(status);
            printf(“child’s pid =%d .exit status=^d\n”,pid,i);
            }
            }
            執(zhí)行
            This is the child process.pid=1501
            This is the parent process .wait for child...
            child’s pid =1501,exit status =5
            waitpid(等待子進(jìn)程中斷或結(jié)束)
            相關(guān)函數(shù) wait,fork
            表頭文件
            #include
            #include
            定義函數(shù) pid_t waitpid(pid_t pid,int * status,int options);
            函數(shù)說明
            waitpid()會暫時停止目前進(jìn)程的執(zhí)行,直到有信號來到或子進(jìn)程
            結(jié)束。如果在調(diào)用wait()時子進(jìn)程已經(jīng)結(jié)束,則wait()會立即
            返回子進(jìn)程結(jié)束狀態(tài)值。子進(jìn)程的結(jié)束狀態(tài)值會由參數(shù)status 返回,
            而子進(jìn)程的進(jìn)程識別碼也會一快返回。如果不在意結(jié)束狀態(tài)值,則
            參數(shù)status 可以設(shè)成NULL。參數(shù)pid 為欲等待的子進(jìn)程識別碼,
            其他數(shù)值意義如下:
            pid0 等待任何子進(jìn)程識別碼為pid 的子進(jìn)程。
            參數(shù)option 可以為0 或下面的OR 組合:
            WNOHANG 如果沒有任何已經(jīng)結(jié)束的子進(jìn)程則馬上返回,不予以
            等待。
            WUNTRACED 如果子進(jìn)程進(jìn)入暫停執(zhí)行情況則馬上返回,但結(jié)束
            狀態(tài)不予以理會。
            子進(jìn)程的結(jié)束狀態(tài)返回后存于status,底下有幾個宏可判別結(jié)束情
            況:
            WIFEXITED(status)如果子進(jìn)程正常結(jié)束則為非0 值。
            WEXITSTATUS(status)取得子進(jìn)程exit()返回的結(jié)束代碼,一
            般會先用WIFEXITED 來判斷是否正常結(jié)束才能使用此宏。
            WIFSIGNALED(status)如果子進(jìn)程是因為信號而結(jié)束則此宏值為

            WTERMSIG(status) 取得子進(jìn)程因信號而中止的信號代碼,一般
            會先用WIFSIGNALED 來判斷后才使用此宏。
            WIFSTOPPED(status) 如果子進(jìn)程處于暫停執(zhí)行情況則此宏值為
            真。一般只有使用WUNTRACED 時才會有此情況。
            WSTOPSIG(status) 取得引發(fā)子進(jìn)程暫停的信號代碼,一般會先
            用WIFSTOPPED 來判斷后才使用此宏。
            返回值
            如果執(zhí)行成功則返回子進(jìn)程識別碼(PID),如果有錯誤發(fā)生則返回
            -1。失敗原因存于errno 中。
            范例
            參考wait()。

            inux的system () 函數(shù)詳解
             
             
            system(執(zhí)行shell 命令)
            相關(guān)函數(shù)
                    fork,execve,waitpid,popen
            表頭文件
                    #i nclude<stdlib.h>
            定義函數(shù)
                    int system(const char * string);
            函數(shù)說明
                    system()會調(diào)用fork()產(chǎn)生子進(jìn)程,由子進(jìn)程來調(diào)用/bin/sh-c string來執(zhí)行參數(shù)string字符串所代表的命令,此命>令執(zhí)行完后隨即返回原調(diào)用的進(jìn)程。在調(diào)用system()期間SIGCHLD 信號會被暫時擱置,SIGINT和SIGQUIT 信號則會被忽略。
            返回值
              =-1:出現(xiàn)錯誤  
              =0:調(diào)用成功但是沒有出現(xiàn)子進(jìn)程  
              >0:成功退出的子進(jìn)程的id
                    如果system()在調(diào)用/bin/sh時失敗則返回127,其他失敗原因返回-1。若參數(shù)string為空指針(NULL),則返回非零值>。 如果system()調(diào)用成功則最后會返回執(zhí)行shell命令后的返回值,但是此返回值也有可能為 system()調(diào)用/bin/sh失敗所返回的127,因此最好能再檢查errno 來確認(rèn)執(zhí)行成功。
            附加說明
                    在編寫具有SUID/SGID權(quán)限的程序時請勿使用system(),system()會繼承環(huán)境變量,通過環(huán)境變量可能會造成系統(tǒng)安全的問題。
            范例
                    #i nclude<stdlib.h>
            main()
            {
            system(“ls -al /etc/passwd /etc/shadow”);
            }
            執(zhí)行結(jié)果:

            -rw-r--r-- 1 root root 705 Sep 3 13 :52 /etc/passwd
            -r--------- 1 root root 572 Sep 2 15 :34 /etc/shado

            例2:

            char tmp[];
            sprintf(tmp,"/bin/mount -t vfat %s /mnt/usb",dev);
            system(tmp);
            其中dev是/dev/sda1。
             


            本文來自CSDN博客,轉(zhuǎn)載請標(biāo)明出處:http://blog.csdn.net/alentam/archive/2008/04/09/2270763.aspx

            久久久久久九九99精品| 久久综合九色综合久99| 女同久久| 欧美黑人激情性久久| 99久久人妻无码精品系列蜜桃| 99久久精品午夜一区二区 | 亚洲а∨天堂久久精品9966| 一本久久a久久精品综合香蕉| 欧美va久久久噜噜噜久久| 热re99久久精品国产99热| 一级A毛片免费观看久久精品| 久久大香香蕉国产| 一本久道久久综合狠狠躁AV| 久久99精品久久久久久| 日日狠狠久久偷偷色综合免费| 无码国内精品久久人妻| 国产精品欧美久久久久天天影视| 久久久无码精品亚洲日韩蜜臀浪潮| 91久久精品无码一区二区毛片| 伊人久久久AV老熟妇色| 亚洲人成网站999久久久综合| 久久国产精品-国产精品| 国产亚洲美女精品久久久2020| 国产激情久久久久影院老熟女| 粉嫩小泬无遮挡久久久久久| 久久SE精品一区二区| 一本久久精品一区二区| 亚洲性久久久影院| 无码精品久久一区二区三区| 99久久免费只有精品国产| 精品久久久久久| 国产亚洲综合久久系列| 久久久久久国产精品无码超碰| 久久人爽人人爽人人片AV| 久久婷婷五月综合97色| 久久一日本道色综合久久| 人妻精品久久久久中文字幕69 | 国产成人精品综合久久久| 国内精品伊人久久久影院| 久久精品国产99国产精品亚洲| 亚洲综合精品香蕉久久网|