• <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++博客 :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

            fork, wait, system

            Posted on 2009-09-28 13:53 Prayer 閱讀(1237) 評(píng)論(0)  編輯 收藏 引用 所屬分類(lèi): 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í)行過(guò)程,就必須先講清楚操作系統(tǒng)中的“進(jìn)程(process)”概念。一個(gè)進(jìn)程,主要包含三個(gè)元素:

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

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

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

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

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

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

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

            我想你比較困惑的就是,為什么看上去程序中互斥的兩個(gè)分支都被執(zhí)行了。在一個(gè)程序的一次執(zhí)行中,這當(dāng)然是不可能的;但是你看到的兩行輸出是來(lái)自?xún)蓚€(gè)進(jìn)程,這兩個(gè)進(jìn)程來(lái)自同一個(gè)程序的兩次執(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);
            }
            程序運(yùn)行結(jié)果如下:
            (fork()運(yùn)行結(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()運(yùn)行結(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ù)的運(yùn)行機(jī)制,拿fork為例,fork()并不是進(jìn)程切換,而是復(fù)制一個(gè)當(dāng)前進(jìn)程。當(dāng)使用pid= fork()時(shí),其實(shí)是創(chuàng)建了兩個(gè)進(jìn)程,這兩個(gè)進(jìn)程有著相同的內(nèi)容,例如變量的值,空間配,特別是正在執(zhí)行的語(yǔ)句等等都相同,但這些內(nèi)容卻在兩個(gè)獨(dú)立的內(nèi) 存空間中。因此當(dāng)執(zhí)行上述代碼時(shí),便相當(dāng)于同一段代碼在兩個(gè)進(jìn)程中執(zhí)行,所有就出現(xiàn)了兩個(gè)結(jié)果,一個(gè)是子進(jìn)程的信息,一個(gè)是父進(jìn)程的信息。再看globa 和var這兩個(gè)變量,由于是兩個(gè)獨(dú)立的進(jìn)程,因此當(dāng)各自執(zhí)行代碼時(shí),變量也不會(huì)互相受到影響,所以在子進(jìn)程中的globa和var均發(fā)生了變化,而在父進(jìn) 程中卻沒(méi)有變化。
                 其次分析一下,fork()和vfork()的區(qū)別:vfork采用寫(xiě)時(shí)拷貝技術(shù)(write-on-copy),父進(jìn)程與子進(jìn)程享用同一個(gè)內(nèi)存空間,因 此,程序中的變量其實(shí)也就是父子進(jìn)程的公共變量,所以,當(dāng)其中一個(gè)進(jìn)程中的變量值發(fā)生改變時(shí),另一個(gè)進(jìn)程中的變量值肯定也跟著發(fā)生變化,另外,兩個(gè)函數(shù)的 區(qū)別還在于vfork用于創(chuàng)建一個(gè)新進(jìn)程,而該新進(jìn)程的目的是exec一個(gè)新進(jìn)程,vfork和fork一樣都創(chuàng)建一個(gè)子進(jìn)程,但是它并不將父進(jìn)程的地址 空間完全復(fù)制到子進(jìn)程中,因?yàn)樽舆M(jìn)程會(huì)立即調(diào)用exec,于是也就不會(huì)存放該地址空間。不過(guò)在子進(jìn)程中調(diào)用exec或exit之前,他在父進(jìn)程的空間中運(yùn) 行。vfork保證子進(jìn)程先運(yùn)行,在她調(diào)用exec exit之后父進(jìn)程才可能被調(diào)度運(yùn)行。如果在調(diào)用這兩個(gè)函數(shù)之前子進(jìn)程依賴(lài)于父進(jìn)程的進(jìn)一步動(dòng)作,則會(huì)導(dǎo)致死鎖。 用fork函數(shù)創(chuàng)建子進(jìn)程后,子進(jìn)程往往要調(diào)用一種exec函數(shù)以執(zhí)行另一個(gè)程序,當(dāng)進(jìn)程調(diào)用一種exec函數(shù)時(shí),該進(jìn)程完全由新程序代換,而新程序則從 其main函數(shù)開(kāi)始執(zhí)行,因?yàn)檎{(diào)用exec并不創(chuàng)建新進(jìn)程,所以前后的進(jìn)程id 并未改變,exec只是用另一個(gè)新程序替換了當(dāng)前進(jìn)程的正文,數(shù)據(jù),堆和棧段。


            wait(等待子進(jìn)程中斷或結(jié)束)
            相關(guān)函數(shù) waitpid,fork
            表頭文件
            #include
            #include
            定義函數(shù) pid_t wait (int * status);
            函數(shù)說(shuō)明
            wait()會(huì)暫時(shí)停止目前進(jìn)程的執(zhí)行,直到有信號(hào)來(lái)到或子進(jìn)程結(jié)
            束。如果在調(diào)用wait()時(shí)子進(jìn)程已經(jīng)結(jié)束,則wait()會(huì)立即返
            回子進(jìn)程結(jié)束狀態(tài)值。子進(jìn)程的結(jié)束狀態(tài)值會(huì)由參數(shù)status 返回,
            而子進(jìn)程的進(jìn)程識(shí)別碼也會(huì)一快返回。如果不在意結(jié)束狀態(tài)值,則
            參數(shù)status 可以設(shè)成NULL。子進(jìn)程的結(jié)束狀態(tài)值請(qǐng)參考waitpid()。
            返回值
            如果執(zhí)行成功則返回子進(jìn)程識(shí)別碼(PID),如果有錯(cuò)誤發(fā)生則返回
            -1。失敗原因存于errno 中。
            附加說(shuō)明
            范例
            #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ù)說(shuō)明
            waitpid()會(huì)暫時(shí)停止目前進(jìn)程的執(zhí)行,直到有信號(hào)來(lái)到或子進(jìn)程
            結(jié)束。如果在調(diào)用wait()時(shí)子進(jìn)程已經(jīng)結(jié)束,則wait()會(huì)立即
            返回子進(jìn)程結(jié)束狀態(tài)值。子進(jìn)程的結(jié)束狀態(tài)值會(huì)由參數(shù)status 返回,
            而子進(jìn)程的進(jìn)程識(shí)別碼也會(huì)一快返回。如果不在意結(jié)束狀態(tài)值,則
            參數(shù)status 可以設(shè)成NULL。參數(shù)pid 為欲等待的子進(jìn)程識(shí)別碼,
            其他數(shù)值意義如下:
            pid0 等待任何子進(jìn)程識(shí)別碼為pid 的子進(jìn)程。
            參數(shù)option 可以為0 或下面的OR 組合:
            WNOHANG 如果沒(méi)有任何已經(jīng)結(jié)束的子進(jìn)程則馬上返回,不予以
            等待。
            WUNTRACED 如果子進(jìn)程進(jìn)入暫停執(zhí)行情況則馬上返回,但結(jié)束
            狀態(tài)不予以理會(huì)。
            子進(jìn)程的結(jié)束狀態(tài)返回后存于status,底下有幾個(gè)宏可判別結(jié)束情
            況:
            WIFEXITED(status)如果子進(jìn)程正常結(jié)束則為非0 值。
            WEXITSTATUS(status)取得子進(jìn)程exit()返回的結(jié)束代碼,一
            般會(huì)先用WIFEXITED 來(lái)判斷是否正常結(jié)束才能使用此宏。
            WIFSIGNALED(status)如果子進(jìn)程是因?yàn)樾盘?hào)而結(jié)束則此宏值為

            WTERMSIG(status) 取得子進(jìn)程因信號(hào)而中止的信號(hào)代碼,一般
            會(huì)先用WIFSIGNALED 來(lái)判斷后才使用此宏。
            WIFSTOPPED(status) 如果子進(jìn)程處于暫停執(zhí)行情況則此宏值為
            真。一般只有使用WUNTRACED 時(shí)才會(huì)有此情況。
            WSTOPSIG(status) 取得引發(fā)子進(jìn)程暫停的信號(hào)代碼,一般會(huì)先
            用WIFSTOPPED 來(lái)判斷后才使用此宏。
            返回值
            如果執(zhí)行成功則返回子進(jìn)程識(shí)別碼(PID),如果有錯(cuò)誤發(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ù)說(shuō)明
                    system()會(huì)調(diào)用fork()產(chǎn)生子進(jìn)程,由子進(jìn)程來(lái)調(diào)用/bin/sh-c string來(lái)執(zhí)行參數(shù)string字符串所代表的命令,此命>令執(zhí)行完后隨即返回原調(diào)用的進(jìn)程。在調(diào)用system()期間SIGCHLD 信號(hào)會(huì)被暫時(shí)擱置,SIGINT和SIGQUIT 信號(hào)則會(huì)被忽略。
            返回值
              =-1:出現(xiàn)錯(cuò)誤  
              =0:調(diào)用成功但是沒(méi)有出現(xiàn)子進(jìn)程  
              >0:成功退出的子進(jìn)程的id
                    如果system()在調(diào)用/bin/sh時(shí)失敗則返回127,其他失敗原因返回-1。若參數(shù)string為空指針(NULL),則返回非零值>。 如果system()調(diào)用成功則最后會(huì)返回執(zhí)行shell命令后的返回值,但是此返回值也有可能為 system()調(diào)用/bin/sh失敗所返回的127,因此最好能再檢查errno 來(lái)確認(rèn)執(zhí)行成功。
            附加說(shuō)明
                    在編寫(xiě)具有SUID/SGID權(quán)限的程序時(shí)請(qǐng)勿使用system(),system()會(huì)繼承環(huán)境變量,通過(guò)環(huán)境變量可能會(huì)造成系統(tǒng)安全的問(wèn)題。
            范例
                    #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。
             


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

            狠狠精品久久久无码中文字幕 | 久久久精品国产Sm最大网站| 久久精品无码专区免费东京热| 久久99精品综合国产首页| 精品国产91久久久久久久a| 久久天天躁狠狠躁夜夜avapp| 国产精品久久久久久| 久久AV无码精品人妻糸列| 99精品久久久久久久婷婷| 狠狠色婷婷久久综合频道日韩| 国产精品美女久久久免费| 婷婷五月深深久久精品| 一级女性全黄久久生活片免费| 久久精品国产一区| 国产成人精品久久二区二区| 怡红院日本一道日本久久| 色综合久久久久综合体桃花网| 青青久久精品国产免费看| 2021久久精品国产99国产精品| 久久精品国产男包| 人妻精品久久久久中文字幕一冢本 | 久久久久国产精品人妻| 午夜精品久久久久久影视777| 精品综合久久久久久97超人| 夜夜亚洲天天久久| 99国内精品久久久久久久| 色婷婷久久综合中文久久一本| 久久综合丝袜日本网| 久久亚洲欧美日本精品| 久久福利资源国产精品999| 国产精品美女久久久网AV| 久久久久久久尹人综合网亚洲| 色综合久久最新中文字幕| 伊人情人综合成人久久网小说| 久久精品夜色噜噜亚洲A∨| 久久亚洲国产中v天仙www| 一本久久a久久精品综合夜夜| 久久不射电影网| 久久综合九色综合欧美狠狠| 久久久久亚洲AV无码专区桃色| 久久成人影院精品777|