• <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>
            隨筆 - 40, 文章 - 0, 評論 - 9, 引用 - 0
            數據加載中……

            unix多進程2

            linux下的多進程編程(2007-5-21,11:17:55)
            什么是一個進程?進程這個概念是針對系統而不是針對用戶的,對用戶來說,他面對的概念是程序。當用戶敲入命令執行一個程序的時候,對系統而言,它將啟動一個進程。但和程序不同的是,在這個進程中,系統可能需要再啟動一個或多個進程來完成獨立的多個任務。多進程編程的主要內容包括進程控制和進程間通信,在了解這些之前,我們先要簡單知道進程的結構。
            2.1 Linux下進程的結構
            Linux下一個進程在內存里有三部分的數據,就是"代碼段"、"堆棧段"和"數據段".其實學過匯編語言的人一定知道,一般的CPU都有上述三種段寄存器,以方便操作系統的運行。這三個部分也是構成一個完整的執行序列的必要的部分。
            "代碼段",顧名思義,就是存放了程序代碼的數據,假如機器中有數個進程運行相同的一個程序nokia s40 主題下載,那么它們就可以使用相同的代碼段。"堆棧段"存放的就是子程序的返回地址、子程序的參數以及程序的局部變量。而數據段則存放程序的全局變量,常數以及動態數據分配的數據空間(比如用malloc之類的函數取得的空間)。這其中有許多細節問題,這里限于篇幅就不多介紹了。系統如果同時運行數個相同的程序,它們之間就不能使用同一個堆棧段和數據段。
            2.2 Linux下的進程控制
            在傳統的Unix環境下,有兩個基本的操作用于創建和修改進程:函數fork( )用來創建一個新的進程,該進程幾乎是當前進程的一個完全拷貝;函數族exec( )用來啟動另外的進程以取代當前運行的進程。Linux的進程控制和傳統的Unix進程控制基本一致,只在一些細節的地方有些區別手機和絢鈴聲,例如在Linux系統中調用vfork和fork完全相同,而在有些版本的Unix系統中,vfork調用有不同的功能。由于這些差別幾乎不影響我們大多數的編程,在這里我們不予考慮。
            2.2.1 fork( )
            fork在英文中是"分叉"的意思。為什么取這個名字呢?因為一個進程在運行中,如果使用了fork,就產生了另一個進程,于是進程就"分叉"了,所以這個名字取得很形象。下面就看看如何具體使用fork,這段程序演示了使用fork的基本框架:
            void main(){
            int i;
            if ( fork() == 0 ) {
            /* 子進程程序 */
            for ( i = 1; i <1000; i ++ ) printf("This is child process ");
            }
            else {
            /* 父進程程序*/
            for ( i = 1; i <1000; i ++ ) printf("This is process process ");
            }
            }
            程序運行后,你就能看到屏幕上交替出現子進程與父進程各打印出的一千條信息了。如果程序還在運行中,你用ps命令就能看到系統中有兩個它在運行了。 那么調用這個fork函數時發生了什么呢?fork函數啟動一個新的進程,前面我們說過,這個進程幾乎是當前進程的一個拷貝:子進程和父進程使用相同的代碼段;子進程復制父進程的堆棧段和數據段。這樣,父進程的所有數據都可以留給子進程,但是,子進程一旦開始運行,雖然它繼承了父進程的一切數據,但實際上數據卻已經分開,相互之間不再有影響了,也就是說,它們之間不再共享任何數據了。它們再要交互信息時,只有通過進程間通信來實現,這將是我們下面的內容。既然它們如此相象,系統如何來區分它們呢?這是由函數的返回值來決定的。對于父進程,fork函數返回了子程序的進程號,而對于子程序中興小靈通來電彩鈴,fork函數則返回零。在操作系統中,我們用ps函數就可以看到不同的進程號,對父進程而言,它的進程號是由比它更低層的系統調用賦予的,而對于子進程而言,它的進程號即是fork函數對父進程的返回值。在程序設計中,父進程和子進程都要調用函數fork()下面的代碼nokia 7650 鈴聲,而我們就是利用fork()函數對父子進程的不同返回值用if……else……語句來實現讓父子進程完成不同的功能,正如我們上面舉的例子一樣。我們看到,上面例子執行時兩條信息是交互無規則的打印出來的cect鈴聲下載,這是父子進程獨立執行的結果,雖然我們的代碼似乎和串行的代碼沒有什么區別。 讀者也許會問,如果一個大程序在運行中,它的數據段和堆棧都很大,一次fork就要復制一次,那么fork的系統開銷不是很大嗎?其實UNIX自有其解決的辦法,大家知道,一般CPU都是以"頁"為單位來分配內存空間的,每一個頁都是實際物理內存的一個映像,象INTEL的CPU,其一頁在通常情況下是4086字節大小,而無論是數據段還是堆棧段都是由許多"頁"構成的,fork函數復制這兩個段,只是"邏輯"上的,并非"物理"上的,也就是說,實際執行fork時,物理空間上兩個進程的數據段和堆棧段都還是共享著的,當有一個進程寫了某個數據時,這時兩個進程之間的數據才有了區別,系統就將有區別的"頁"從物理上也分開。系統在空間上的開銷就可以達到最小。
               下面演示一個足以"搞死"Linux的小程序,其源代碼非常簡單:
              void main()
               {
                 for( ; ; ) fork();
               }
              這個程序什么也不做,就是死循環地fork,其結果是程序不斷產生進程,而這些進程又不斷產生新的進程,很快,系統的進程就滿了,系統就被這么多不斷產生的進程"撐死了"。當然只要系統管理員預先給每個用戶設置可運行的最大進程數,這個惡意的程序就完成不了企圖了。
               2.2.2 exec( )函數族
              下面我們來看看一個進程如何來啟動另一個程序的執行。在Linux中要使用exec函數族。系統調用execve()對當前進程進行替換,替換者為一個指定的程序,其參數包括文件名(filename)、參數列表(argv)以及環境變量(envp)。exec函數族當然不止一個,但它們大致相同,在Linux中,它們分別是:execl,execlp搞笑寶寶彩鈴,execle,execv,execve和execvp,下面我只以execlp為例,其它函數究竟與execlp有何區別,請通過manexec命令來了解它們的具體情況。
              一個進程一旦調用exec類函數,它本身就"死亡"了,系統把代碼段替換成新的程序的代碼,廢棄原有的數據段和堆棧段,并為新程序分配新的數據段與堆棧段,唯一留下的,就是進程號,也就是說,對系統而言,還是同一個進程,不過已經是另一個程序了。(不過exec類函數中有的還允許繼承環境變量之類的信息。)
              那么如果我的程序想啟動另一程序的執行但自己仍想繼續運行的話,怎么辦呢?那就是結合fork與exec的使用。下面一段代碼顯示如何啟動運行其它程序:char command[256];
            void main()
            {
            int rtn; /*子進程的返回數值*/
            while(1) {
            /* 從終端讀取要執行的命令 */
            printf( ">" );
            fgets( command, 256, stdin );
            command[strlen(command)-1] = 0;
            if ( fork() == 0 ) {
            /* 子進程執行此命令 */
            execlp( command, command );
            /* 如果exec函數返回,表明沒有正常執行命令,打印錯誤信息*/
            perror( command );
            exit( errorno );
            }
            else {
            /* 父進程, 等待子進程結束,并打印子進程的返回值 */
            wait ( &rtn );
            printf( " child process return %d ",. rtn );
            }
            }
            }
              此程序從終端讀入命令并執行之,執行完成后,父進程繼續等待從終端讀入命令。熟悉DOS和WINDOWS系統調用的朋友一定知道DOS/WINDOWS也有exec類函數,其使用方法是類似的天津聯通鈴音下載,但DOS/WINDOWS還有spawn類函數,因為DOS是單任務的系統,它只能將"父進程"駐留在機器內再執行"子進程",這就是spawn類的函數。WIN32已經是多任務的系統了,但還保留了spawn類函數,WIN32中實現spawn函數的方法同前述UNIX中的方法差不多,開設子進程后父進程等待子進程結束后才繼續運行。UNIX在其一開始就是多任務的系統,所以從核心角度上講不需要spawn類函數。
              在這一節里,我們還要講講system()和popen()函數。system()函數先調用fork(),然后再調用exec()來執行用戶的登錄shell,通過它來查找可執行文件的命令并分析參數,最后它么使用wait()函數族之一來等待子進程的結束。函數popen()和函數system()相似,不同的是它調用pipe()函數創建一個管道,通過它來完成程序的標準輸入和標準輸出。這兩個函數是為那些不太勤快的程序員設計的,在效率和安全方面都有相當的缺陷,在可能的情況下,應該盡量避免。
            Linux聯盟收集整理

            http://www.allegations.com.cn/baidu/8003/982.htm

            posted on 2007-12-18 15:41 閱讀(520) 評論(0)  編輯 收藏 引用 所屬分類: liunx編程技術

            久久亚洲AV成人无码国产| 亚洲精品乱码久久久久久久久久久久| 思思久久好好热精品国产| 国产精品成人99久久久久| 久久精品国产亚洲综合色| 久久国产精品一区二区| 国产成人久久激情91| 久久96国产精品久久久| 国产精品xxxx国产喷水亚洲国产精品无码久久一区 | MM131亚洲国产美女久久| 国产人久久人人人人爽| 久久国产免费观看精品| 国产精品九九久久免费视频 | 26uuu久久五月天| 久久久久综合国产欧美一区二区| 国产精品99久久不卡| 香港aa三级久久三级老师2021国产三级精品三级在 | 久久精品午夜一区二区福利| 99久久婷婷国产综合亚洲| 久久免费精品视频| 久久久亚洲精品蜜桃臀| 97视频久久久| 久久久久久亚洲Av无码精品专口| 69SEX久久精品国产麻豆| 国内精品伊人久久久久影院对白| 日韩久久久久中文字幕人妻| 久久久精品人妻一区二区三区蜜桃 | 精品熟女少妇av免费久久| 色偷偷888欧美精品久久久| 欧美亚洲国产精品久久久久| 99精品久久久久中文字幕| 人人狠狠综合久久亚洲高清| 人人狠狠综合久久88成人| 久久精品亚洲精品国产欧美| 久久综合九色综合网站| 久久国产精品免费一区| 久久天堂AV综合合色蜜桃网| 亚洲精品无码久久久久AV麻豆| 久久成人国产精品二三区| 久久人人爽人人人人片av| 精品久久久久久久久久久久久久久|