linux 有名管道(FIFO)


http://blog.csdn.net/firefoxbug/article/details/8137762

 

linux 有名管道(FIFO)

 

管道的緩沖區是有限的(管道制存在於內存中,在管道創建時,為緩沖區分配一個頁面大小)
管道所傳送的是無格式字節流,這就要求管道的讀出方和寫入方必須事先約定好數據的格式,比如多少字節算作一個消息(或命令、或記錄)等等

多個寫進程,一個讀進程。可以參考我之前的博客http://blog.csdn.net/firefoxbug/article/details/7358715

  • 如果當前打開操作是為讀而打開FIFO時,若已經有相應進程為寫而打開該FIFO,則當前打開操作將成功返回;否則,可能阻塞直到有相應進程為寫而打開該FIFO(當前打開操作設置了阻塞標志);或者,成功返回(當前打開操作沒有設置阻塞標志)。
  • 如果當前打開操作是為寫而打開FIFO時,如果已經有相應進程為讀而打開該FIFO,則當前打開操作將成功返回;否則,可能阻塞直到有相應進程為讀而打開該FIFO(當前打開操作設置了阻塞標志);或者,返回ENXIO錯誤(當前打開操作沒有設置阻塞標志)。

一旦設置了阻塞標志,調用mkfifo建立好之后,那么管道的兩端讀寫必須分別打開,有任何一方未打開,則在調用open的時候就阻塞。

約定:如果一個進程為了從FIFO中讀取數據而阻塞打開FIFO,那么稱該進程內的讀操作為設置了阻塞標志的讀操作。(意思就是我現在要打開一個有名管道來讀數據!)

 

可以理解為管道的兩端都建立好了,但是寫端還沒開始寫數據!)

      則對於設置了阻塞標志的讀操作來說,將一直阻塞(

就是block住了,等待數據。它並不消耗CPU資源,這種進程的同步方式對CPU而言是非常有效率的。)

  • 對於沒有設置阻塞標志讀操作來說則返回-1,當前errno值為EAGAIN,提醒以后再試。

造成阻塞的原因有兩種

      FIFO內有數據,但有其它進程在讀這些數據(

對於各個讀進程而言,這根有名管道是臨界資源,大家得互相謙讓,不能一起用。)

  • FIFO內沒有數據。解阻塞的原因則是FIFO中有新的數據寫入,不論信寫入數據量的大小,也不論讀操作請求多少數據量。

注:如果FIFO中有數據,則設置了阻塞標志的讀操作不會因為FIFO中的字節數小於請求讀的字節數而阻塞,此時,讀操作會返回FIFO中現有的數據量。

約定:如果一個進程為了向FIFO中寫入數據而阻塞打開FIFO,那么稱該進程內的寫操作為設置了阻塞標志的寫操作。(意思就是我現在要打開一個有名管道來寫數據!)

 

 

  • 當要寫入的數據量不大於PIPE_BUF 時,linux將保證寫入的原子性。如果此時管道空閑緩沖區不足以容納要寫入的字節數,則進入睡眠,直到當緩沖區中能夠容納要寫入的字節數時,才開始進行 一次性寫操作。(PIPE_BUF ==>> /usr/include/linux/limits.h)
  • 當要寫入的數據量大於PIPE_BUF時,linux將不再保證寫入的原子性。FIFO緩沖區一有空閑區域,寫進程就會試圖向管道寫入數據,寫操作在寫完所有請求寫的數據后返回。

 

  • 當要寫入的數據量大於PIPE_BUF時,linux將不再保證寫入的原子性。在寫滿所有FIFO空閑緩沖區后,寫操作返回。
  • 當要寫入的數據量不大於PIPE_BUF時,linux將保證寫入的原子性。如果當前FIFO空閑緩沖區能夠容納請求寫入的字節數,寫完后成功返回;如果當前FIFO空閑緩沖區不能夠容納請求寫入的字節數,則返回EAGAIN錯誤,提醒以后再寫;

設置了阻塞標志

 

if (buf_to_write <=  PIPE_BUF) 		//寫入的數據量不大於PIPE_BUF時
then
	if ( buf_to_write > system_buf_left )	//保證寫入的原子性,要么一次性把buf_to_write全都寫完,要么一個字節都不寫!
	then
		block ;
		until ( buf_to_write <= system_buf_left );
		goto write ;
	else
		write ;
	fi
else
	write ; //不管怎樣,就是不斷寫,知道把緩沖區寫滿了才阻塞
fi

管道寫端 pipe_read.c

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
//pipe_read.c

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <fcntl.h>  
#include <limits.h>  
#include <sys/types.h>  
#include <sys/stat.h>  
  
#define FIFO_NAME "/tmp/my_fifo"  
#define BUFFER_SIZE PIPE_BUF  
  
int main()  
{  
    int pipe_fd;  
    int res;  
  
    int open_mode = O_RDONLY;  
    char buffer[BUFFER_SIZE 1];  
    int bytes 0;  
  
    memset(buffer'\0'sizeof(buffer));  
  
    printf("Process %d opeining FIFO O_RDONLY\n", getpid());  
    pipe_fd = open(FIFO_NAME, open_mode);  
    printf("Process %d result %d\n", getpid(), pipe_fd);  
  
    if (pipe_fd != -1)  
    {  
        do{  
            res = read(pipe_fd, buffer, BUFFER_SIZE);  
            bytes += res;  
        printf("%d\n",bytes);
        }while(res 0);  
        close(pipe_fd);  
    }  
    else  
    {  
        exit(EXIT_FAILURE);  
    }  
  
    printf("Process %d finished, %d bytes read\n", getpid(), bytes);  
    exit(EXIT_SUCCESS);  
}

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

管道讀端 pipe_write.c

//pipe_write.c

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <fcntl.h>  
#include <limits.h>  
#include <sys/types.h>  
#include <sys/stat.h>  
  
#define FIFO_NAME "/tmp/my_fifo"  
#define BUFFER_SIZE PIPE_BUF  
#define TEN_MEG (1024 * 100)  
  
int main()  
{  
    int pipe_fd;  
    int res;  
    int open_mode = O_WRONLY;  
  
    int bytes 0;  
    char buffer[BUFFER_SIZE 1];  
  
    if (access(FIFO_NAME, F_OK== -1)  
    {  
        res = mkfifo(FIFO_NAME0777);  
        if (res != 0)  
        {  
            fprintf(stderr"Could not create fifo %s\n", FIFO_NAME);  
            exit(EXIT_FAILURE);  
        }  
    }  
  
    printf("Process %d opening FIFO O_WRONLY\n", getpid());  
    pipe_fd = open(FIFO_NAME, open_mode);  
    printf("Process %d result %d\n", getpid(), pipe_fd);  
  
   //sleep(20);
    if (pipe_fd != -1)  
    {  
        while (bytes < TEN_MEG)  
        {  
            res = write(pipe_fd, buffer, BUFFER_SIZE);  
            if (res == -1)  
            {  
                fprintf(stderr"Write error on pipe\n");  
                exit(EXIT_FAILURE);  
            }  
            bytes += res;  
        printf("%d\n",bytes);
        }  
        close(pipe_fd);  
    }  
    else  
    {  
        exit(EXIT_FAILURE);  
    }  
  
    printf("Process %d finish\n", getpid());  
    exit(EXIT_SUCCESS);  
}
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM