文章目錄
- 題目描述
- 代碼實現
- 關于pipe函數
- 關于讀寫操作
- 關于讀寫端口
- 關于wait函數
- 功能:
- 注意:
- 關于fork函數
題目描述
編寫一個程序,利用管道實現父子進程的通信,父進程向子進程發送信息,由子進程輸出顯示。
代碼實現
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> //管道功能所在的頭文件
#include <sys/types.h> //wait函數所在的頭文件
#include <sys/wait.h> //wait函數所在的頭文件#define MAXLINE 80int main()
{int n; //所發送消息的長度int fd[2]; //管道讀寫端口pid_t pid; //進程號char line[MAXLINE]; //消息緩沖區if(pipe(fd) < 0) //建立管道不成功{perror("pipe");exit(1); //有錯誤型的退出}if((pid = fork()) < 0) //建立子進程不成功{perror("fork:");exit(1);}else //成功建立子進程{ if(pid > 0) //父進程{close(fd[0]); //關閉讀端write(fd[1],"I love CMY!\n", 12); //把"I love CMY!\n"長度為12的字符送到管道寫端口fd[1]close(fd[1]); //關閉寫端,老師是要求寫完之后要關閉的,但是我試了試不寫也沒啥問題……wait(NULL); //父進程等待子進程結束}else //子進程{close(fd[1]); //關閉寫端n = read(fd[0], line, MAXLINE); //從管道讀端口fd[0]把長度為MAXLINE的字符送到line中write(STDOUT_FILENO, line, n); //將line中長度為n的字符寫到標準輸出設備(即屏幕上)close(fd[0]); //同上,關閉讀端,老師是要求寫完之后要關閉的,但是我試了試不寫也沒啥問題……} }return 0;
}
關于pipe函數
功能:創建一個普通管道
關于讀寫操作
也就是說讀/寫操作的流程是:
- 關閉讀/寫端
- 進行寫/讀操作
- 寫/讀完關閉寫/讀端
關于讀寫端口
為什么fd[0]是讀,fd[1]是寫,能不能顛倒過來?
一般來講,我們常說:讀寫讀寫,不說寫讀寫讀,因為不順口。所以0是讀,1是寫,你要是想顛倒也是可以的,只要你自己記得住就行。
關于wait函數
功能:
父進程一旦調用了wait就立即阻塞自己,由wait自動分析是否當前進程的某個子進程已經退出,如果讓它找到了這樣一個已經變成僵尸的子進程,wait就會收集這個子進程的信息,并把它徹底銷毀后返回;如果沒有找到這樣一個子進程,wait就會一直阻塞在這里,直到有一個出現為止。
注意:
當父進程沒有用wait()函數等待已終止的子進程時,子進程就會進入一種無父進程的狀態,此時子進程就是僵尸進程。
如果先終止父進程,子進程依然會繼續正常進行,只是它將由init進程(PID 1)繼承,當子進程終止時,init進程捕獲這個狀態。
關于fork函數
其實本題就是管道和父子進程的相結合,重點是理解fork()
之后父子進程的并行執行
,以老師PPT中的例題為例:
子進程執行的是 val == 0 的內容,而父進程執行的是 val > 0 的內容,子進程創建的時候完全復制了父進程的資源,可以理解為自 val = fork() 之后,代碼就被copy了一份一摸一樣的,父進程執行被copy的,子進程執行copy的。而對于本題而言,從
if((pid = fork()) < 0) //建立子進程不成功
開始,子進程copy了后面的代碼,而且繼承了父進程之前的資源,如變量
等,然后在接下來的代碼中根據pid的不同進入不同的代碼段。
值得注意的是,本題代碼中先處理的是父進程的寫操作,再處理的是子進程的讀操作,那如果反過來先寫子進程的讀操作,再寫父進程的寫操作,代碼還可以正常運行嗎?
經過測試,答案是可以,因為我們剛講過他們倆是并行執行
嘛,但是根據先寫進去再讀出來比較符合人類的思維,所以我們本題就先寫父進程的寫操作,再處理子進程的讀操作~
證據如下圖: