原創(chuàng)|其它|編輯:郝浩|2011-07-08 17:30:02.000|閱讀 912 次
概述:本文主要介紹如何通過管道和重定向?qū)崿F(xiàn)linux管道命令,希望對大家有幫助。
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
下午查看了自己當(dāng)初寫的一個有關(guān)管道的一個題目,這個題目是帶領(lǐng)3+1學(xué)習(xí)管道通信時寫的。題目要求如下:
題目2:通過管道模擬shell命令:cat file | sort
涉及主要知識點:未命名管道、重定向
題目描述:具體模擬一個shell命令:cat file | sort。具體的一些提示在后面。
提示:首先在當(dāng)前目錄下創(chuàng)建一個名為”file”的文件,里面的內(nèi)容輸入如下:
99
123
892
12
1342
89
32
76
通過執(zhí)行”cat file | sort”后的結(jié)果如下:
12
123
1342
32
76
89
892
99
現(xiàn)在我們需要通過一個管道,將”cat file”的結(jié)果通過管道送給命令”sort”。其中,將”cat file”命令的輸出結(jié)果重定向到”sort”命令的輸入是由包含在命令中的管道標(biāo)志”|”來完成的。為了在程序當(dāng)中實現(xiàn)類似的功能,需要用dup()或者dup2()系統(tǒng)調(diào)用將標(biāo)準(zhǔn)輸入和標(biāo)準(zhǔn)輸出聯(lián)系起來,具體的系統(tǒng)調(diào)用使用可以通過man手冊來查,或者查閱群共享里面的函數(shù)手冊。另外,這里的”cat file”和”sort”命令不是自己來完成,而是通過調(diào)用exec函數(shù)族來實現(xiàn)的,具體的exec()函數(shù)族的使用不再啰嗦。
擴展:實現(xiàn)兩個管道
今天下午仔細(xì)一琢磨,發(fā)現(xiàn)這個題目當(dāng)中,沒有把創(chuàng)建進程說明,怪不得當(dāng)初其他人做這個題目時,有許多疑問,原來是我的題目出現(xiàn)了問題。
自己下午實現(xiàn)了一下,程序代碼如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
int main()
{
int fd[2], res;
pid_t pid;
res = pipe(fd);
if(res == -1) {
perror("Pipe error!");
exit(1);
}
pid = fork();
if(pid > 0) {
close(fd[1]);
dup2(fd[0], 0);
execl("/usr/bin/sort", "sort", (char *)0);
wait(NULL);
exit(0);
} else if(pid == 0) {
dup2(fd[1], 1);
close(fd[0]);
execl("/bin/cat", "cat", "file", NULL);
exit(0);
} else {
perror("Fork error!");
exit(2);
}
}
我當(dāng)初出這個程序的目的主要是想把管道應(yīng)用起來,然后想讓大家能夠把重定向帶出來,而且我發(fā)現(xiàn)許多有關(guān)linux C語言的書上基本都有這種類似的題目,所以我覺得這個題目挺好的。
說一下我的思路吧,針對這個題,首先得把"cat file | sort"這個命令搞清楚,應(yīng)該明確:這里有兩個進程,而不是一個進程,其實我原先把題目在無意當(dāng)中暗示了只有一個進程。在程序當(dāng)中,創(chuàng)建一個進程之后,子進程將會執(zhí)行“cat file”命令,而父進程會執(zhí)行“sort”命令。在子進程當(dāng)中,會通過重定向"dup2(fd[1], 1)",將標(biāo)準(zhǔn)輸出重定向到管道的寫端,說通俗一些,就是以后對于標(biāo)準(zhǔn)輸出的操作都就改為對管道的寫端的操作了,如果對這里還是不能夠理解的話,請查看我的前一篇“通過文件共享來學(xué)習(xí)I/O重定向(下)——I/O重定向”。對于父進程而言,也是通關(guān)重定向“dup2(fd[0], 0)”,將標(biāo)準(zhǔn)輸入重定向到管道的讀端,以后對于標(biāo)準(zhǔn)輸入的操作都就改為了對于fd[0]的操作了。
通過這么解釋,應(yīng)該對于上面的程序清楚了吧,下面把我調(diào)試的過程當(dāng)中發(fā)現(xiàn)的一些問題總結(jié)一下。
1.execl()函數(shù)執(zhí)行之后,該進程成為什么進程了?
對于這個問題的回答,我們可以通過修改上面的程序來實現(xiàn),把父進程調(diào)用execl()函數(shù)之前加一個sleep(5)函數(shù),即,
if(pid > 0) {
close(fd[1]);
dup2(fd[0], 0); //修改的內(nèi)容
execl("/usr/bin/sort", "sort", (char *)0);
wait(NULL);
exit(0);
} else if(pid == 0) {
在一個終端執(zhí)行這個程序,在5秒之內(nèi)打開另外一個終端,執(zhí)行“ps -au”,并分析其結(jié)果,發(fā)現(xiàn)有這么幾條記錄:
sunny 5107 0.0 0.0 1616 308 pts/0 S+ 21:36 0:00 ./a.out
sunny 5108 0.0 0.0 0 0 pts/0 Z+ 21:36 0:00 [cat] <defunct>
sunny 5109 0.0 0.1 2716 1072 pts/2 R+ 21:37 0:00 ps -au
在其中有一個<defunct>標(biāo)識,說明出現(xiàn)了僵尸進程。
上面的測試,是讓子進程去執(zhí)行“execl()”函數(shù)的時候,父進程等待等待5s,然后在另外一個終端下查看子進程成了什么樣的進程,結(jié)果是僵尸進程。等整個程序執(zhí)行完畢之后,發(fā)現(xiàn)僵尸進程消失了,那么僵尸進程是如何消失的呢?這個目前我還沒有弄明白,希望大家指教(對于popen()出現(xiàn)僵尸進程之后,會通過close()函數(shù)來退出,但是這里的話,好像沒有close()函數(shù)調(diào)用,那它是如何退出呢?)。
2.出現(xiàn)僵尸進程之后,那么下面的代碼還執(zhí)行嗎?
答案是不執(zhí)行。
這次我們修改子進程的代碼:
} else if(pid == 0) {
dup2(fd[1], 1);
close(fd[0]);
execl("/bin/cat", "cat", "file", NULL);
printf("fffffffffffffffffffffff"); //運行之后,發(fā)現(xiàn)這句沒有執(zhí)行
exit(0);
} else {
為什么會不執(zhí)行了,我是這樣猜想的,當(dāng)子進程去執(zhí)行“cat”命令時,執(zhí)行完之 后,它成了僵尸進程,之后它退出了,但是如何退出的?
我在網(wǎng)上找到了有關(guān)進程一生的描述:隨著一句fork,一個新進程呱呱落地,但它這時只是老進程的一個克隆。然后隨著exec,新進程脫胎換骨,離家獨立,開始了為人民服務(wù)的職業(yè)生涯。人有生老病死,進程也一樣,它可以是自然死亡,即運行到main函數(shù)的最后一個”}”,從容地離我們而去;也可以是自殺,自殺有2種方式,一種是調(diào)用 exit函數(shù),一種是在main函數(shù)內(nèi)使用return,無論哪一種方式,它都可以留下遺書,放在返回值里保留下來;它還甚至能可被謀殺,被其它進程通過 另外一些方式結(jié)束他的生命。進程死掉以后,會留下一具僵尸,wait和waitpid充當(dāng)了殮尸工,把僵尸推去火化,使其最終歸于無形。這里遺書中的內(nèi)容是在進程列表中保留一個位置,記載該進程的退出狀態(tài)等信息供其他 進程收集,除此之外,僵尸進程不再占有任何內(nèi)存空間。
看到這里,我明白了,子進程成為僵尸進程的原因是由于沒有進行“遺書”回收造成的,為了證實我的想法,我們繼續(xù)將父進程要執(zhí)行的代碼修改如下:
if(pid > 0) {
close(fd[1]);
dup2(fd[0], 0);
wait(NULL);
sleep(3);
execl("/usr/bin/sort", "sort", (char *)0);
printf("ffffffffffffffff\n");
exit(0);
} else if(pid == 0) {
這時,當(dāng)父進程等待3s的時候,在另外一個終端使用ps查看的時候,法相那個僵尸進程不見了,這說明我們對產(chǎn)生的僵尸進程進行了回收。但是,這時候,當(dāng)sleep()執(zhí)行完了之后,父進程自己又成了僵尸進程,它會被誰回收呢?當(dāng)我們程序當(dāng)中的父進程成為僵尸進程之后,它會把自己的遺書交給它的父進程,應(yīng)該是在shell中執(zhí)行那個程序的進程吧,所以,它應(yīng)該是由執(zhí)行它的那個shell進程回收的。
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉(zhuǎn)載自:網(wǎng)絡(luò)轉(zhuǎn)載