1. 程式人生 > >嵌入式Linux併發程式設計,程序間通訊方式,無名管道,無名管道特點,無名管道建立pipe(),獲取管道大小,管道斷裂

嵌入式Linux併發程式設計,程序間通訊方式,無名管道,無名管道特點,無名管道建立pipe(),獲取管道大小,管道斷裂

1,Linux下的程序間通訊機制

Linux下的程序間通訊機制 應用
早期UNIX程序間通訊方式(很多是從Unix繼承的) 無名管道(pipe) 本地通訊,用於一臺計算機內部不同程序之間的通訊
有名管道 (fifo)
訊號(signal)
System V IPC(系統5的IPC機制) 共享記憶體(share memory)
訊息佇列(message queue)
訊號燈集(semaphore set)
套接字(socket) 既可以進行本地通訊,更多的是多臺主機之間通過網路通訊

2,無名管道

在這裡插入圖片描述

  1. 執行緒共享同一個地址空間,所以執行緒之間交換資料很方便,最簡單的就是建一個全域性的緩衝區
  2. 每個程序有自己獨立的地址空間,是私有的,有自己的程式碼,有自己的資料,所以程序之間要通訊,要交換資料就需要專門的通訊機制來實現,無名管道就是其中最簡單的一種

無名管道特點

  1. 只能用於具有親緣關係的程序(父子程序,祖孫程序,兄弟程序)之間的通訊:管道建立好之後,雖然返回兩個檔案描述符,但是無名管道不像普通檔案有路徑,在檔案系統中是不可見的,僅僅在記憶體中存在,並且無名管道是某一個程序建立的,其他程序想要開啟無名管道,只能通過繼承的方式開啟其他程序建立的無名管道
  2. 單工的通訊模式,具有固定的讀端和寫端:如父程序寫管道,子程序讀管道;或子程序寫管道,父程序讀管道;雙向的資料通訊要通過兩個無名管道來實現
  3. 無名管道建立時會返回兩個檔案描述符,分別用於讀寫管道

建立無名管道pipe()

#include <unistd.h> int pipe(int pfd[2]);

  1. 成功時返回0,失敗時返回EOF
  2. pfd 包含兩個元素的整形陣列,用來儲存檔案描述符
  3. pfd[0]用於讀管道;pfd[1]用於寫管道

無名管道通訊

在這裡插入圖片描述

3,無名管道示例

子程序1和子程序2分別往管道中寫入字串;父程序讀管道內容並列印;

#include <stdio.h>
#include <stdlib.h> #include <unistd.h> #include <sys/types.h> int main(void) { pid_t pid1, pid2; char buf[32]; int pfd[2]; if (pipe(pfd) < 0) //先建立無名管道,後建立子程序 { perror(“pipe”); exit(-1); } if ((pid1 = fork()) < 0) { perror(“fork”); exit(-1); } else if (pid1 == 0) { // 子程序1 strcpy(buf, “I’m process1”); write(pfd[1], buf, 32); exit(0); } else { // 父程序 if ((pid2 = fork()) < 0) { perror(“fork”); exit(-1); } else if (pid2 == 0) { // 子程序2 sleep(1); strcpy(buf, “I’m process 2); write(pfd[1], buf, 32); } else { // 父程序 wait(NULL);//程序回收,哪個先結束回收哪個 read(pfd[0], buf, 32);//管道中的內容讀走之後,管道中就沒內容了 printf(%s\n”, buf); wait(NULL); read(pfd[0], buf, 32); printf(%s\n”, buf); } } return 0; }

4,無名管道詳解

操作 情況 狀態
讀無名管道 寫端存在(至少有一個程序可以通過檔案描述符寫管道) 有資料 管道中的資料比程序讀管道指定的大小多 read返回實際讀取的位元組數
管道中的資料比程序希望要讀取的資料少
無資料 程序讀阻塞
寫端不存在 有資料 read返回實際讀取的位元組數
無資料 (不阻塞)read返回0
寫無名管道 讀端存在(至少有一個程序可以通過檔案描述符讀管道內容) 有空間 write返回實際寫入的位元組數
無空間 空間不足(管道中的剩餘空間比程序寫管道需要的空間小) 系統不保證原子操作(能寫多少寫多少,然後程序寫阻塞)
無空間(經過多次寫之後,管道中一點空間都沒有了) 程序寫阻塞
讀端不存在 有空間 管道斷裂(系統不允許任何程序寫一個沒有讀端的管道)
無空間

如何獲取無名管道的大小?

  1. 迴圈寫入管道,直到阻塞
  2. 統計迴圈次數
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main(int argc, const char *argv[])
{
	int count=0,num=0,bytes=0,pfd[2];
	char buf[1024];

	if(pipe(pfd) < 0)
	{
		perror("pipe");
		exit(-1);
	}
	while(1)
	{
		bytes = write(pfd[1],buf,1024);
		num += bytes;
		printf("num:%d   bytes:%d    wrote %d k bytes\n",num,bytes,++count);
	}

	return 0;
}
[email protected]:~/test/pthread$ gcc pipe_size.c -o pipe_size.out
[email protected]:~/test/pthread$ ./pipe_size.out 
num:1024   bytes:1024    wrote 1 k bytes
num:2048   bytes:1024    wrote 2 k bytes
.
.
.
num:64512   bytes:1024    wrote 63 k bytes
num:65536   bytes:1024    wrote 64 k bytes

  • Linux建立的管道預設大小64k位元組

如何驗證管道斷裂(程序被訊號結束)?

  1. 子程序寫管道
  2. 父程序回收
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main(int argc, const char *argv[])
{
	pid_t pid;
	int pfd[2],status;
	char buf[32];

	if(pipe(pfd) < 0)
	{
		perror("pipe");
		exit(-1);
	}
	close(pfd[0]);
	if((pid = fork()) < 0)
	{
		perror("fork");
		exit(-1);
	}
	else if(pid == 0)
	{
		write(pfd[1],buf,32);
		exit(0);
	}
	else
	{
		wait(&status);
		printf("status %#x\n",status);
	}

	return 0;
}
[email protected]:~/test/pthread$ gcc pipe_broken.c -o pipe_broken.out
[email protected]:~/test/pthread$ ./pipe_broken.out 
status 0xd
  • status的值不為零,說明程序被訊號打斷,status的值就是訊號的型別

使用kill -l檢視當前系統中所有的訊號型別

[email protected]:~/test/pthread$ kill -l
 1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL	 5) SIGTRAP
 6) SIGABRT	 7) SIGBUS	 8) SIGFPE	 9) SIGKILL	10) SIGUSR1
11) SIGSEGV	12) SIGUSR2	13) SIGPIPE	14) SIGALRM	15) SIGTERM
16) SIGSTKFLT	17) SIGCHLD	18) SIGCONT	19) SIGSTOP	20) SIGTSTP
21) SIGTTIN	22) SIGTTOU	23) SIGURG	24) SIGXCPU	25) SIGXFSZ
26) SIGVTALRM	27) SIGPROF	28) SIGWINCH	29) SIGIO	30) SIGPWR
31) SIGSYS	34) SIGRTMIN	35) SIGRTMIN+1	36) SIGRTMIN+2	37) SIGRTMIN+3
38) SIGRTMIN+4	39) SIGRTMIN+5	40) SIGRTMIN+6	41) SIGRTMIN+7	42) SIGRTMIN+8
43) SIGRTMIN+9	44) SIGRTMIN+10	45) SIGRTMIN+11	46) SIGRTMIN+12	47) SIGRTMIN+13
48) SIGRTMIN+14	49) SIGRTMIN+15	50) SIGRTMAX-14	51) SIGRTMAX-13	52) SIGRTMAX-12
53) SIGRTMAX-11	54) SIGRTMAX-10	55) SIGRTMAX-9	56) SIGRTMAX-8	57) SIGRTMAX-7
58) SIGRTMAX-6	59) SIGRTMAX-5	60) SIGRTMAX-4	61) SIGRTMAX-3	62) SIGRTMAX-2
63) SIGRTMAX-1	64) SIGRTMAX	
  • 0xd是13,可以看到13對應的訊號型別是SIGPIPE,這個訊號通常就代表管道斷裂