青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Prayer

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

exec函數(shù)族

Posted on 2009-04-15 23:01 Prayer 閱讀(3487) 評論(0)  編輯 收藏 引用 所屬分類: LINUX/UNIX/AIX

也許有不少讀者從本系列文章一推出就開始讀,一直到這里還有一個很大的疑惑:既然所有新進(jìn)程都是由fork產(chǎn)生的,而且由fork產(chǎn)生的子進(jìn)程和父進(jìn)程幾乎完全一樣,那豈不是意味著系統(tǒng)中所有的進(jìn)程都應(yīng)該一模一樣了嗎?而且,就我們的常識來說,當(dāng)我們執(zhí)行一個程序的時候,新產(chǎn)生的進(jìn)程的內(nèi)容應(yīng)就是程序的內(nèi)容才對。是我們理解錯了嗎?顯然不是,要解決這些疑惑,就必須提到我們下面要介紹的exec系統(tǒng)調(diào)用。

1.10.1 簡介

說是exec系統(tǒng)調(diào)用,實際上在Linux中,并不存在一個exec()的函數(shù)形式,exec指的是一組函數(shù),一共有6個,分別是:

#include <unistd.h>
            int execl(const char *path, const char *arg, ...);
            int execlp(const char *file, const char *arg, ...);
            int execle(const char *path, const char *arg, ..., char *const envp[]);
            int execv(const char *path, char *const argv[]);
            int execvp(const char *file, char *const argv[]);
            int execve(const char *path, char *const argv[], char *const envp[]);
            

其中只有execve是真正意義上的系統(tǒng)調(diào)用,其它都是在此基礎(chǔ)上經(jīng)過包裝的庫函數(shù)。

exec函數(shù)族的作用是根據(jù)指定的文件名找到可執(zhí)行文件,并用它來取代調(diào)用進(jìn)程的內(nèi)容,換句話說,就是在調(diào)用進(jìn)程內(nèi)部執(zhí)行一個可執(zhí)行文件。這里的可執(zhí)行文件既可以是二進(jìn)制文件,也可以是任何Linux下可執(zhí)行的腳本文件。

與一般情況不同,exec函數(shù)族的函數(shù)執(zhí)行成功后不會返回,因為調(diào)用進(jìn)程的實體,包括代碼段,數(shù)據(jù)段和堆棧等都已經(jīng)被新的內(nèi)容取代,只留下進(jìn)程ID等一些表面上的信息仍保持原樣,頗有些神似"三十六計"中的"金蟬脫殼"??瓷先ミ€是舊的軀殼,卻已經(jīng)注入了新的靈魂。只有調(diào)用失敗了,它們才會返回一個-1,從原程序的調(diào)用點接著往下執(zhí)行。

現(xiàn)在我們應(yīng)該明白了,Linux下是如何執(zhí)行新程序的,每當(dāng)有進(jìn)程認(rèn)為自己不能為系統(tǒng)和擁護(hù)做出任何貢獻(xiàn)了,他就可以發(fā)揮最后一點余熱,調(diào)用任何一個exec,讓自己以新的面貌重生;或者,更普遍的情況是,如果一個進(jìn)程想執(zhí)行另一個程序,它就可以fork出一個新進(jìn)程,然后調(diào)用任何一個exec,這樣看起來就好像通過執(zhí)行應(yīng)用程序而產(chǎn)生了一個新進(jìn)程一樣。

事實上第二種情況被應(yīng)用得如此普遍,以至于Linux專門為其作了優(yōu)化,我們已經(jīng)知道,fork會將調(diào)用進(jìn)程的所有內(nèi)容原封不動的拷貝到新產(chǎn)生的子進(jìn)程中去,這些拷貝的動作很消耗時間,而如果fork完之后我們馬上就調(diào)用exec,這些辛辛苦苦拷貝來的東西又會被立刻抹掉,這看起來非常不劃算,于是人們設(shè)計了一種"寫時拷貝(copy-on-write)"技術(shù),使得fork結(jié)束后并不立刻復(fù)制父進(jìn)程的內(nèi)容,而是到了真正實用的時候才復(fù)制,這樣如果下一條語句是exec,它就不會白白作無用功了,也就提高了效率。

1.10.2 稍稍深入

上面6條函數(shù)看起來似乎很復(fù)雜,但實際上無論是作用還是用法都非常相似,只有很微小的差別。在學(xué)習(xí)它們之前,先來了解一下我們習(xí)以為常的main函數(shù)。

下面這個main函數(shù)的形式可能有些出乎我們的意料:

int main(int argc, char *argv[], char *envp[])
            

它可能與絕大多數(shù)教科書上描述的都不一樣,但實際上,這才是main函數(shù)真正完整的形式。

參數(shù)argc指出了運行該程序時命令行參數(shù)的個數(shù),數(shù)組argv存放了所有的命令行參數(shù),數(shù)組envp存放了所有的環(huán)境變量。環(huán)境變量指的是一組值,從用戶登錄后就一直存在,很多應(yīng)用程序需要依靠它來確定系統(tǒng)的一些細(xì)節(jié),我們最常見的環(huán)境變量是PATH,它指出了應(yīng)到哪里去搜索應(yīng)用程序,如/bin;HOME也是比較常見的環(huán)境變量,它指出了我們在系統(tǒng)中的個人目錄。環(huán)境變量一般以字符串"XXX=xxx"的形式存在,XXX表示變量名,xxx表示變量的值。

值得一提的是,argv數(shù)組和envp數(shù)組存放的都是指向字符串的指針,這兩個數(shù)組都以一個NULL元素表示數(shù)組的結(jié)尾。

我們可以通過以下這個程序來觀看傳到argc、argv和envp里的都是什么東西:

/* main.c */
            int main(int argc, char *argv[], char *envp[])
            {
            printf("\n### ARGC ###\n%d\n", argc);
            printf("\n### ARGV ###\n");
            while(*argv)
            printf("%s\n", *(argv++));
            printf("\n### ENVP ###\n");
            while(*envp)
            printf("%s\n", *(envp++));
            return 0;
            }
            

編譯它:

$ cc main.c -o main
            

運行時,我們故意加幾個沒有任何作用的命令行參數(shù):

$ ./main -xx 000
            ### ARGC ###
            3
            ### ARGV ###
            ./main
            -xx
            000
            ### ENVP ###
            PWD=/home/lei
            REMOTEHOST=dt.laser.com
            HOSTNAME=localhost.localdomain
            QTDIR=/usr/lib/qt-2.3.1
            LESSOPEN=|/usr/bin/lesspipe.sh %s
            KDEDIR=/usr
            USER=lei
            LS_COLORS=
            MACHTYPE=i386-redhat-linux-gnu
            MAIL=/var/spool/mail/lei
            INPUTRC=/etc/inputrc
            LANG=en_US
            LOGNAME=lei
            SHLVL=1
            SHELL=/bin/bash
            HOSTTYPE=i386
            OSTYPE=linux-gnu
            HISTSIZE=1000
            TERM=ansi
            HOME=/home/lei
            PATH=/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/home/lei/bin
            _=./main
            

我們看到,程序?qū)?./main"作為第1個命令行參數(shù),所以我們一共有3個命令行參數(shù)。這可能與大家平時習(xí)慣的說法有些不同,小心不要搞錯了。

現(xiàn)在回過頭來看一下exec函數(shù)族,先把注意力集中在execve上:

int execve(const char *path, char *const argv[], char *const envp[]);
            

對比一下main函數(shù)的完整形式,看出問題了嗎?是的,這兩個函數(shù)里的argv和envp是完全一一對應(yīng)的關(guān)系。execve第1個參數(shù)path是被執(zhí)行應(yīng)用程序的完整路徑,第2個參數(shù)argv就是傳給被執(zhí)行應(yīng)用程序的命令行參數(shù),第3個參數(shù)envp是傳給被執(zhí)行應(yīng)用程序的環(huán)境變量。

留心看一下這6個函數(shù)還可以發(fā)現(xiàn),前3個函數(shù)都是以execl開頭的,后3個都是以execv開頭的,它們的區(qū)別在于,execv開頭的函數(shù)是以"char *argv[]"這樣的形式傳遞命令行參數(shù),而execl開頭的函數(shù)采用了我們更容易習(xí)慣的方式,把參數(shù)一個一個列出來,然后以一個NULL表示結(jié)束。這里的NULL的作用和argv數(shù)組里的NULL作用是一樣的。

在全部6個函數(shù)中,只有execle和execve使用了char *envp[]傳遞環(huán)境變量,其它的4個函數(shù)都沒有這個參數(shù),這并不意味著它們不傳遞環(huán)境變量,這4個函數(shù)將把默認(rèn)的環(huán)境變量不做任何修改地傳給被執(zhí)行的應(yīng)用程序。而execle和execve會用指定的環(huán)境變量去替代默認(rèn)的那些。

還有2個以p結(jié)尾的函數(shù)execlp和execvp,咋看起來,它們和execl與execv的差別很小,事實也確是如此,除execlp和execvp之外的4個函數(shù)都要求,它們的第1個參數(shù)path必須是一個完整的路徑,如"/bin/ls";而execlp和execvp的第1個參數(shù)file可以簡單到僅僅是一個文件名,如"ls",這兩個函數(shù)可以自動到環(huán)境變量PATH制定的目錄里去尋找。

1.10.3 實戰(zhàn)

知識介紹得差不多了,接下來我們看看實際的應(yīng)用:

/* exec.c */
            #include <unistd.h>
            main()
            {
            char *envp[]={"PATH=/tmp",
            "USER=lei",
            "STATUS=testing",
            NULL};
            char *argv_execv[]={"echo", "excuted by execv", NULL};
            char *argv_execvp[]={"echo", "executed by execvp", NULL};
            char *argv_execve[]={"env", NULL};
            if(fork()==0)
            if(execl("/bin/echo", "echo", "executed by execl", NULL)<0)
            perror("Err on execl");
            if(fork()==0)
            if(execlp("echo", "echo", "executed by execlp", NULL)<0)
            perror("Err on execlp");
            if(fork()==0)
            if(execle("/usr/bin/env", "env", NULL, envp)<0)
            perror("Err on execle");
            if(fork()==0)
            if(execv("/bin/echo", argv_execv)<0)
            perror("Err on execv");
            if(fork()==0)
            if(execvp("echo", argv_execvp)<0)
            perror("Err on execvp");
            if(fork()==0)
            if(execve("/usr/bin/env", argv_execve, envp)<0)
            perror("Err on execve");
            }
            

程序里調(diào)用了2個Linux常用的系統(tǒng)命令,echo和env。echo會把后面跟的命令行參數(shù)原封不動的打印出來,env用來列出所有環(huán)境變量。

由于各個子進(jìn)程執(zhí)行的順序無法控制,所以有可能出現(xiàn)一個比較混亂的輸出--各子進(jìn)程打印的結(jié)果交雜在一起,而不是嚴(yán)格按照程序中列出的次序。

編譯并運行:

$ cc exec.c -o exec
            $ ./exec
            executed by execl
            PATH=/tmp
            USER=lei
            STATUS=testing
            executed by execlp
            excuted by execv
            executed by execvp
            PATH=/tmp
            USER=lei
            STATUS=testing
            

果然不出所料,execle輸出的結(jié)果跑到了execlp前面。

大家在平時的編程中,如果用到了exec函數(shù)族,一定記得要加錯誤判斷語句。因為與其他系統(tǒng)調(diào)用比起來,exec很容易受傷,被執(zhí)行文件的位置,權(quán)限等很多因素都能導(dǎo)致該調(diào)用的失敗。最常見的錯誤是:

  1. 找不到文件或路徑,此時errno被設(shè)置為ENOENT;
  2. 數(shù)組argv和envp忘記用NULL結(jié)束,此時errno被設(shè)置為EFAULT;
  3. 沒有對要執(zhí)行文件的運行權(quán)限,此時errno被設(shè)置為EACCES。

原文出自http://www-128.ibm.com/developerworks/cn/linux/kernel/syscall/part3/index.html

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            国产一区在线看| 亚洲精品网站在线播放gif| 在线观看成人网| 国产综合香蕉五月婷在线| 国产一区二区日韩精品| 国产亚洲一区在线播放| 国内精品久久久| 亚洲国产精品精华液网站| 91久久精品网| 亚洲一区高清| 久久蜜桃资源一区二区老牛| 欧美成人午夜剧场免费观看| 亚洲国产aⅴ天堂久久| 91久久线看在观草草青青| 99精品欧美一区二区三区综合在线| 亚洲美女毛片| 久久精品成人一区二区三区| 欧美日本精品| 狠狠色噜噜狠狠狠狠色吗综合| 亚洲激情小视频| 中国成人黄色视屏| 国产精品夜夜夜| 在线日韩av| 在线亚洲观看| 久久久人成影片一区二区三区观看| 男同欧美伦乱| 一区二区三区免费在线观看| 欧美自拍偷拍午夜视频| 欧美色欧美亚洲另类七区| 亚洲综合日韩| 亚洲一二三四久久| 欧美电影免费观看高清完整版| 日韩写真视频在线观看| 久久影院亚洲| 午夜欧美大尺度福利影院在线看| 欧美91大片| 亚洲电影免费观看高清完整版在线观看| 一道本一区二区| 亚洲黄色免费| 亚洲免费视频成人| 欧美激情一区二区三区四区| 国产乱码精品一区二区三区不卡 | 国产三区二区一区久久| 亚洲精品日韩一| 久久久久国产精品厨房| 中文国产一区| 欧美日韩第一区日日骚| 亚洲区免费影片| 毛片一区二区三区| 翔田千里一区二区| 国产欧美成人| 亚洲欧美日韩在线观看a三区| 亚洲国产日韩综合一区| 久久久久久久尹人综合网亚洲 | 一区二区三区视频在线观看| 欧美风情在线观看| 亚洲精品一区在线| 亚洲国产成人av在线| 久久中文久久字幕| 亚洲风情在线资源站| 久久综合久久88| 久久久九九九九| 一区二区三区在线视频播放| 久久久久久婷| 欧美一区二区大片| 国产一区二区在线观看免费| 欧美一区二区播放| 中文网丁香综合网| 国产精品高清在线观看| 免费成人性网站| 久久精品观看| 亚洲裸体视频| 欧美图区在线视频| 欧美一区观看| 久久av一区二区| 国内精品亚洲| 开心色5月久久精品| 免费不卡中文字幕视频| 亚洲精品一线二线三线无人区| 亚洲精品日韩久久| 国产精品久久久久久久app| 午夜日韩在线| 久久精品国产亚洲高清剧情介绍| 亚洲高清一二三区| 日韩视频一区二区在线观看| 国产精品毛片a∨一区二区三区| 亚洲欧美一级二级三级| 欧美在线短视频| 亚洲黄色小视频| 亚洲美女中出| 国产综合18久久久久久| 亚洲国产精品久久久久秋霞不卡| 欧美日韩国产黄| 午夜精品在线视频| 日韩午夜激情电影| 国产精品久久久久久影视| 午夜精品久久一牛影视| 久久久精品日韩欧美| 在线午夜精品自拍| 欧美伊人久久久久久午夜久久久久| 影音先锋在线一区| 亚洲青色在线| 国产女精品视频网站免费| 欧美成年视频| 国产精品乱码妇女bbbb| 欧美成人自拍| 国产欧美日韩精品丝袜高跟鞋| 免播放器亚洲| 国产精品美女久久久浪潮软件| 免费成人高清| 国产精品中文字幕在线观看| 亚洲第一精品在线| 国产一区三区三区| 亚洲精品老司机| 亚洲女人天堂成人av在线| 在线观看欧美黄色| 亚洲午夜一二三区视频| 一区二区三区中文在线观看 | 欧美在线亚洲| 亚洲综合日韩在线| 欧美日韩一区二区三区在线| 久久综合九色99| 国产精品欧美日韩一区| 亚洲日本va午夜在线电影| 亚洲第一福利社区| 久久综合99re88久久爱| 国产精品久久网| 欧美激情1区2区| 一本色道久久综合亚洲精品按摩 | 亚洲第一在线视频| 久久久久一区二区| 亚洲高清电影| 亚洲尤物精选| 久久综合九九| 欧美特黄一区| 伊人久久大香线蕉av超碰演员| 伊人久久大香线蕉综合热线| 一区二区三区久久| 久久精品视频在线播放| 亚洲国产成人午夜在线一区| 日韩视频亚洲视频| 久久综合亚州| 国产日韩亚洲欧美精品| 亚洲私人影院在线观看| 欧美成人一区二区三区| 亚洲午夜一区二区三区| 欧美精品日韩一本| 精品51国产黑色丝袜高跟鞋| 亚洲欧美日韩国产精品| 亚洲高清资源| 欧美紧缚bdsm在线视频| 1000部国产精品成人观看| 久久精品综合| 欧美一区二区国产| 国产精品一区二区久久国产| 亚洲欧美日韩另类| 亚洲午夜精品网| 国产精品私拍pans大尺度在线 | 亚洲国产成人久久综合| 欧美一级片久久久久久久| 国产精品三级视频| 久久久亚洲高清| 老司机午夜精品视频| 亚洲国产精品成人| 中文国产一区| 韩国精品久久久999| 欧美激情va永久在线播放| 欧美体内she精视频| 久久久天天操| 欧美精品一区二区三区久久久竹菊 | 国产农村妇女毛片精品久久莱园子| 亚洲午夜未删减在线观看| 午夜精品福利在线| 精品二区视频| 一区二区三区免费网站| 亚洲成在人线av| 欧美一区二区三区在线播放| 亚洲激情欧美激情| 欧美一区二区三区在线看| 一本久久综合亚洲鲁鲁五月天| 亚洲欧美日韩国产另类专区| 亚洲人成精品久久久久| 欧美一区二区久久久| 亚洲欧美美女| 欧美日韩在线一区二区三区| 久热精品在线视频| 韩日精品视频| 久久精品五月婷婷| 久久久久亚洲综合| 好吊日精品视频| 欧美一区三区三区高中清蜜桃 | 国产精品视频自拍| 91久久精品视频| 欧美在线免费视屏| 久久精品国产亚洲一区二区三区| 欧美精品福利视频| 亚洲精品中文字幕有码专区| 亚洲欧洲精品一区二区三区不卡| 欧美1级日本1级| 亚洲高清色综合|