文章目錄
- 1.管道是什么
- 2.匿名管道(父子行程通信)
- ①匿名管道原理
- ②pipe函式 (unistd.h) 創建匿名管道
- 確認讀寫行程,關閉對應讀寫端
- 父子行程匿名管道通信代碼
- 3.管道對臨界資源的保護(同步與互斥)
- 4.命名管道(任意兩個行程通信)
- ①mkfifo函式(sys/type.h sys/stat.h)
- ②命名管道練習:利用管道實作行程A向行程B發送字串
1.管道是什么
兩個行程通過打開同一個”檔案“來實作行程間通信,
其中一個行程向檔案里寫入資料,另一個行程通過檔案讀取資料,
或者一個行程向檔案里讀取資料,另一個行程通過檔案寫入資料,
把從一個行程連接到另一個行程的一個這個“檔案”稱為一個管道
根據上面的分析可知,管道只能單向通信
2.匿名管道(父子行程通信)
①匿名管道原理
在我們創建子行程的時候,子行程會共享父行程的資料,當修改行程資料時發生寫時拷貝,當父行程打開檔案后再創建子行程,檔案描述符資訊也會被子行程接受到,兩個行程通過檔案描述符就可以找到同一個檔案,就可以實作資料通信

②pipe函式 (unistd.h) 創建匿名管道
函式原型:
int pipe(int fd[2]);
引數意義:
fd為輸出型引數,傳入fd陣列后,當函式呼叫結束后fd[0]表示讀端,fd[1]表示寫端,
fd陣列中保存的是檔案描述符
回傳值:
成功回傳0,失敗回傳-1

確認讀寫行程,關閉對應讀寫端
因為管道只能單向通信,所以當我們呼叫pipe后創建子行程后會出現下圖狀況

這時要確認讀寫行程,并且關閉對應的讀寫段,
eg:父行程要讀取管道資料,此時關閉父行程的fd[1],子行程要向管道寫入資料,關閉子行程的fd[0].

父子行程匿名管道通信代碼
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<stdlib.h>
int main()
{
int fd[2]={0};
if(pipe(fd)<0)
{
perror("pipe error\n");
}
pid_t id=fork();
if(id==0)
{
//child
close(fd[0]);//子行程關閉讀端
const char* Str="Hello Linux";
for(int i=0;i<10;i++)
{
write(fd[1],Str,strlen(Str));//向管道寫入資料
sleep(1);
}
close(fd[1]);
exit(0);
}
//father
close(fd[1]);
char buff[32]={0};
while(1)
{
ssize_t ReadSize=read(fd[0],buff,sizeof(buff));
if(ReadSize>0)//讀取到資料
{
buff[ReadSize]='\0';//補充字串接受的標準
printf("receive:%s\n",buff);
}
else if(ReadSize==0)//讀取結束
{
printf("read end!\n");
break;
}
else //讀取失敗
{
perror("read error!\n");
break;
}
}
waitpid(id,NULL,0);//父行程阻塞式等待
return 0;
}

注意:
1.實作父子行程不可以通過設定全域變數的方式來實作,因為在創建子行程后,為了保持行程獨立性,子行程在修改資料時會發生寫時拷貝,此時父子行程的全域變數不是同一份了,
2.如果寫端關閉,此時讀端read會回傳0代表檔案結束
3.當管道檔案為空時,此時讀取行程掛起等待寫入,當管道檔案寫滿時,此時寫入行程掛起等待讀取,
4.當管道讀取行程被關閉,此時管道寫入行程會被作業系統終止,因為寫入的資料無意義,
3.管道對臨界資源的保護(同步與互斥)
在多執行流下,父子行程看到的同一份資源稱為臨界資源,
eg:
當子行程正在向管道中寫入資料,父行程此時不能進入管道中讀取資料,
理由:
管道內部提供了互斥與同步機制,管道檔案為空時,此時父行程的read函式會被阻塞不再讀取,
4.命名管道(任意兩個行程通信)
命名管道有檔案名,多個行程可以通過打開同一個檔案,來讓不同行程訪問同一份資源,
①mkfifo函式(sys/type.h sys/stat.h)
函式原型
int mkfifo(const char*Pathname,mode_t mode);
引數解釋:
Pathname:創建命名管道的路徑和名稱,
mode:創建命名管道的檔案權限
回傳值:創建成功回傳0,失敗回傳-1,
②命名管道練習:利用管道實作行程A向行程B發送字串
因為我們要讓不同行程找到相同的管道檔案,所以將兩個行程所需要的檔案名以及頭檔案放到Common.c中
Common.c
#pragma once
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#define FIFE_NAME "MyFiFo"
server是創建管道檔案,并且讀取管道檔案的資料,將這些資料列印到顯示幕上
#include"Commmen.c"
int main()
{
if(mkfifo(FIFE_NAME,0664)<0)//創建管道檔案
{
perror("make fifo error\n");
return 1;
}
int fd=open(FIFE_NAME,O_RDONLY);//打開管道檔案,只讀取
if(fd<0)
{
perror("open error\n");
return 2;
}
char buff[32]={0};
while(1)
{
buff[0]='\0';//每次情況字串
ssize_t size=read(fd,buff,sizeof(buff)-1);//讀取字串放到buff緩沖區中,空余一個空間存放'\0'
if(size>0)//讀取成功
{
buff[size]='\0';//為字串添加'\0'
printf("client:%s\n",buff);
}
else if(size==0)//管道關閉
{
printf("End Client\n");
break;
}
else //讀取失敗
{
perror("read error\n");
break;
}
}
close(fd);
return 0;
}
client是讀取鍵盤上的字符,并且將這些字符寫到管道檔案中,
client.c
#include"Commmen.c"
int main()
{
int fd=open(FIFE_NAME,O_WRONLY);//通過寫的方式打開管道檔案
if(fd<0)
{
perror("open error\n");
return 1;
}
char buff[32]={0};
while(1)
{
printf("Enter String\n");
buff[0]='\0';//清空字符緩沖區
ssize_t size=read(0,buff,sizeof(buff));//0為標準輸入的檔案描述符,讀取鍵盤輸入的字符
if(size>0)
{
buff[size]='\0';
write(fd,buff,strlen(buff)-1);//向管道檔案中寫入buff陣列的資料
}
else
{
printf("error wirte\n");
}
}
close(fd);
return 0;
}
運行結果:

注意:當我們向管道檔案寫入而不讀取時,管道檔案的大小并不會發生變化,這些資料保存在系統中,沒有重繪到磁盤中,雙方通信在記憶體中通信
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/351028.html
標籤:其他
上一篇:函式與遞回
下一篇:預處理,編譯,匯編,鏈接
