• <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++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

            fork, wait, system

            Posted on 2009-09-28 13:53 Prayer 閱讀(1227) 評論(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的執行過程,就必須先講清楚操作系統中的“進程(process)”概念。一個進程,主要包含三個元素:

            o. 一個可以執行的程序;
            o. 和該進程相關聯的全部數據(包括變量,內存空間,緩沖區等等);
            o. 程序的執行上下文(execution context)。

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

            一個稱為“程序計數器(program counter, pc)”的寄存器,指出當前占用 CPU的進程要執行的下一條指令的位置。

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

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

            父進程繼續執行,操作系統對fork的實現,使這個調用在父進程中返回剛剛創建的子進程的pid(一個正整數),所以下面的if語句中pid<0, pid==0的兩個分支都不會執行。所以輸出i am the parent process...

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

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


            #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);
            }
            程序運行結果如下:
            (fork()運行結果)
            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()運行結果)
            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函數的運行機制,拿fork為例,fork()并不是進程切換,而是復制一個當前進程。當使用pid= fork()時,其實是創建了兩個進程,這兩個進程有著相同的內容,例如變量的值,空間配,特別是正在執行的語句等等都相同,但這些內容卻在兩個獨立的內 存空間中。因此當執行上述代碼時,便相當于同一段代碼在兩個進程中執行,所有就出現了兩個結果,一個是子進程的信息,一個是父進程的信息。再看globa 和var這兩個變量,由于是兩個獨立的進程,因此當各自執行代碼時,變量也不會互相受到影響,所以在子進程中的globa和var均發生了變化,而在父進 程中卻沒有變化。
                 其次分析一下,fork()和vfork()的區別:vfork采用寫時拷貝技術(write-on-copy),父進程與子進程享用同一個內存空間,因 此,程序中的變量其實也就是父子進程的公共變量,所以,當其中一個進程中的變量值發生改變時,另一個進程中的變量值肯定也跟著發生變化,另外,兩個函數的 區別還在于vfork用于創建一個新進程,而該新進程的目的是exec一個新進程,vfork和fork一樣都創建一個子進程,但是它并不將父進程的地址 空間完全復制到子進程中,因為子進程會立即調用exec,于是也就不會存放該地址空間。不過在子進程中調用exec或exit之前,他在父進程的空間中運 行。vfork保證子進程先運行,在她調用exec exit之后父進程才可能被調度運行。如果在調用這兩個函數之前子進程依賴于父進程的進一步動作,則會導致死鎖。 用fork函數創建子進程后,子進程往往要調用一種exec函數以執行另一個程序,當進程調用一種exec函數時,該進程完全由新程序代換,而新程序則從 其main函數開始執行,因為調用exec并不創建新進程,所以前后的進程id 并未改變,exec只是用另一個新程序替換了當前進程的正文,數據,堆和棧段。


            wait(等待子進程中斷或結束)
            相關函數 waitpid,fork
            表頭文件
            #include
            #include
            定義函數 pid_t wait (int * status);
            函數說明
            wait()會暫時停止目前進程的執行,直到有信號來到或子進程結
            束。如果在調用wait()時子進程已經結束,則wait()會立即返
            回子進程結束狀態值。子進程的結束狀態值會由參數status 返回,
            而子進程的進程識別碼也會一快返回。如果不在意結束狀態值,則
            參數status 可以設成NULL。子進程的結束狀態值請參考waitpid()。
            返回值
            如果執行成功則返回子進程識別碼(PID),如果有錯誤發生則返回
            -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);
            }
            }
            執行
            This is the child process.pid=1501
            This is the parent process .wait for child...
            child’s pid =1501,exit status =5
            waitpid(等待子進程中斷或結束)
            相關函數 wait,fork
            表頭文件
            #include
            #include
            定義函數 pid_t waitpid(pid_t pid,int * status,int options);
            函數說明
            waitpid()會暫時停止目前進程的執行,直到有信號來到或子進程
            結束。如果在調用wait()時子進程已經結束,則wait()會立即
            返回子進程結束狀態值。子進程的結束狀態值會由參數status 返回,
            而子進程的進程識別碼也會一快返回。如果不在意結束狀態值,則
            參數status 可以設成NULL。參數pid 為欲等待的子進程識別碼,
            其他數值意義如下:
            pid0 等待任何子進程識別碼為pid 的子進程。
            參數option 可以為0 或下面的OR 組合:
            WNOHANG 如果沒有任何已經結束的子進程則馬上返回,不予以
            等待。
            WUNTRACED 如果子進程進入暫停執行情況則馬上返回,但結束
            狀態不予以理會。
            子進程的結束狀態返回后存于status,底下有幾個宏可判別結束情
            況:
            WIFEXITED(status)如果子進程正常結束則為非0 值。
            WEXITSTATUS(status)取得子進程exit()返回的結束代碼,一
            般會先用WIFEXITED 來判斷是否正常結束才能使用此宏。
            WIFSIGNALED(status)如果子進程是因為信號而結束則此宏值為

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

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

            -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博客,轉載請標明出處:http://blog.csdn.net/alentam/archive/2008/04/09/2270763.aspx

            国内精品久久久久久中文字幕 | 国产午夜精品久久久久九九| 久久精品成人免费观看97| 亚洲狠狠婷婷综合久久久久| 精品国产福利久久久| 久久精品卫校国产小美女| 久久这里只有精品久久| 国产午夜久久影院| 亚洲日韩欧美一区久久久久我| 亚洲国产精品婷婷久久| 97久久超碰国产精品2021| 天天躁日日躁狠狠久久| 精品久久久久久久久久中文字幕| 97精品依人久久久大香线蕉97 | 青青草原综合久久大伊人| 久久青青草原精品国产不卡| 99久久国产综合精品成人影院| 国产A三级久久精品| 久久国产综合精品五月天| 精品久久久久久亚洲| 99精品久久久久久久婷婷| 亚洲国产高清精品线久久| 国产999精品久久久久久| 97久久超碰国产精品2021| 久久综合给久久狠狠97色| 久久人人爽人人爽人人AV东京热 | 手机看片久久高清国产日韩| 亚洲欧美国产精品专区久久| 观看 国产综合久久久久鬼色 欧美 亚洲 一区二区 | 久久亚洲AV无码精品色午夜麻豆| 99热精品久久只有精品| 久久99精品久久久久久动态图| 久久ZYZ资源站无码中文动漫| 久久亚洲欧美国产精品| 久久精品国产清自在天天线| 久久只有这里有精品4| 亚洲av日韩精品久久久久久a| 久久久久99这里有精品10| 久久午夜无码鲁丝片秋霞| 伊人久久大香线蕉精品不卡| 色综合久久夜色精品国产|