Linux IPC Practice (2)--Anonymous pipe

Source: Internet
Author: User
Tags posix

Piping Concepts

Pipelines are the oldest form of interprocess communication in Unix, and we refer to a data flow from one process to another as a "pipe", the essence of which is a fixed-size kernel buffer ;

such as: PS aux | grep httpd | awk ' {print $} '  

Pipe limits

1) The pipe is half-duplex , the data can only flow in one direction, need to establish two pipelines when the two sides communicate;

2) Anonymous pipelines can only be used to communicate between processes that have a common ancestor , such as the parent process and the fork-out child process, because the pipe creates two file descriptors that are directly inaccessible to different processes; [Typically, a pipeline is created by a process, and then the process calls fork, and then the parent-child process shares the pipeline]

Anonymous piping pipe

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

Create a nameless pipe

Parameters

PIPEFD: An array of file descriptors, where pipefd[0] represents the read end, Pipefd[1] represents the write end

Pipeline creation



/** Example:    Send a data pipeline from a child process to a parent process such as the second image above **/int main () {int fd[2];    if (pipe (FD) = =-1) err_exit ("Pipe error");    pid_t pid = fork ();    if (PID = =-1) err_exit ("fork Error");   if (PID = = 0)//Sub-process: Writes data to the pipeline {close (fd[0]);        Turn off read-only String str ("Message from Child process!");  Write (Fd[1], str.c_str (), str.size ());        Write data to write end fd[1] Close (fd[1]);    Exit (exit_success);   }//Parent process: Read data from the pipeline close (fd[1]);    Close write-end char Buf[bufsiz] = {0};    Read (Fd[0], buf, sizeof (BUF));    Close (fd[0]); cout << buf << Endl;} 
/** Example: Pipe emulation: ls | Wc-w Run 1. The child process runs the LS2. The parent process runs WC-W3. Through the pipeline, the output of the child process is sent to the input of the WC **/int main () {    int pipefd[2];    if (pipe (PIPEFD) = =-1)        err_exit ("pipe error");    pid_t pid = fork ();    if (PID = =-1)        err_exit ("fork Error");    if (PID = = 0)   //Sub    -process {        close (pipefd[0]);   Turn off read        //Make Stdout_fileno also point to pipefd[1], that is, the output of the LS command will print to the pipeline        dup2 (pipefd[1], Stdout_fileno);//You can close the pipe write end at this time        Close (pipefd[1]);        EXECLP ("/bin/ls", "ls", NULL);        If the process image substitution fails, the following error message is printed        cerr << "Child EXECLP Error" << Endl;;        Exit (exit_failure);    }    Parent process    Close (pipefd[1]);   Close the Write end    //Make Stdin_fileno also point to pipefd[2], i.e. the WC command will read the input    dup2 (pipefd[0], Stdin_fileno) from the pipeline;    Close (pipefd[0]);    EXECLP ("/USR/BIN/WC", "WC", "-w", NULL);    Cerr << "Parent EXECLP error" << Endl;    Exit (exit_failure);}

Anonymous pipe Read and write rules

Rule 1) When the pipe is empty

O_nonblock Disable:read Call blocking, that is, the process pauses execution until the data arrives.

the O_nonblock enable:read call returns a -1,errno value of eagain.

Verify that int main () {int pipefd[2];    if (pipe (PIPEFD)! = 0) err_exit ("Pipe error");    pid_t pid = fork ();    if (PID = =-1) err_exit ("fork Error");        if (PID = = 0)//in Child, Write pipe {sleep (10);   Close (pipefd[0]);        Close Read Pipe String str ("I Can Write pipe from child!");    Write (Pipefd[1],str.c_str (), str.size ());        Write to pipe close (pipefd[1]);    Exit (exit_success);   }//in Parent, Read pipe Close (pipefd[1]);    Close Write pipe char buf[1024] = {0}; Set Read PIPEFD unblock! See what the difference is between the following four lines of statement comments//INT flags = FCNTL (PIPEFD[0],F_GETFL, 0);//Flags |= o_nonblock;//if (Fcntl (pipefd[0],f_set    fl,flags) = =-1)//Err_exit ("Set UnBlock error");    int readcount = Read (pipefd[0],buf,sizeof (BUF));    Read from Pipe if (Readcount < 0)//read returns immediately, no longer waiting for the child process to send data err_exit ("read error");    cout << "Read from pipe:" << buf << Endl; Close (pipefd[0]);}

Rule 2) when the pipe is full

O_nonblock Disable:write Call blocked until a process reads the data.

O_nonblock Enable: Call returns -1,errno value of Eagain

/** Validation Rule 2) simultaneously tests the capacity of the pipeline **/int main () {    if (signal (sigpipe, handler) = = Sig_err)        err_exit ("Signal error");    int pipefd[2];    if (pipe (PIPEFD)! = 0)        err_exit ("pipe error");    Set the write end of the pipeline to non-blocking mode    //After the following three lines of comments see the effect    int flags = FCNTL (pipefd[1], F_GETFL, 0);    if (Fcntl (pipefd[1], F_SETFL, flags| O_nonblock) = =-1)        err_exit ("Fcntl set Error");    int count = 0;    while (true)    {        if (write (pipefd[1], "A", 1) = =-1)        {            cerr << "Write pipe error:" << strer Ror (errno) << Endl;            break;        }        + + count;    }    cout << "Pipe size =" << count << Endl;}

3) If the file descriptor for all the pipe writes is closed, read returns 0

Validation Rule 3) int main () {    int pipefd[2];    if (pipe (PIPEFD)! = 0)        err_exit ("pipe error");    pid_t pid = fork ();    if (PID = =-1)        err_exit ("fork Error");    else if (PID = = 0)    {        close (pipefd[1]);        Exit (exit_success);    }    Close (pipefd[1]);    Sleep (2);    Char buf[2];    if (read (pipefd[0], buf, sizeof (BUF)) = = 0)        cout << "sure" << Endl;}

4) The write operation generates a signal if the file descriptor corresponding to the read end of all the pipes is closed sigpipe

Validation rule 4) int main () {    if (signal (sigpipe, handler) = = Sig_err)        err_exit ("Signal error");    int pipefd[2];    if (pipe (PIPEFD)! = 0)        err_exit ("pipe error");    pid_t pid = fork ();    if (PID = =-1)        err_exit ("fork Error");    else if (PID = = 0)    {        close (pipefd[0]);        Exit (exit_success);    }    Close (pipefd[0]);    Sleep (2);    char test;    if (write (pipefd[1], &test, sizeof (test)) < 0)        err_exit ("write Error");}

Linux Pipe Features

1) When the amount of data to be written is not greater than pipe_buf , Linux guarantees the atomicity of the write.

2) Linux will no longer guarantee the atomicity of writes when the amount of data to be written is greater than pipe_buf.


Man Description:

posix.1-2001 says that write (2) s of less than Pipe_buf bytes must is atomic:

The output data is written to the pipe as a contiguous sequence.

Writes of more than Pipe_buf bytes could be nonatomic:

The kernel may interleave the data with data written by other processes.

POSIX.1-2001 requires PIPE_BUF to is at least bytes.

(On Linux, Pipe_buf is 4096 bytes. In Linux, Pipe_buf is 4 bytes).

The precise semantics depend on whether the file descriptor is non-blocking (O_nonblock),

Whether there is multiple writers to the pipe, and on N, the number of bytes to be written:

O_nonblock Disabled (blocked), n <= pipe_buf

all n bytes is written atomically; Write (2) may block if there was not a guest for n bytes to be written immediately

O_nonblock enabled (non-blocking), n <= pipe_buf

If There is a to write n bytes to the pipe and then write (2) succeeds immediately, writing all n bytes;

otherwise write (2) fails, with errno set to Eagain (note: If there is not enough space to write data, a byte is not written and a direct error is returned).

O_nonblock disabled, n > Pipe_buf

The Write is nonatomic:the data given to write (2) may be interleaved with write (2) s by other process;

The Write (2) blocks until n bytes has been written.

O_nonblock enabled, n > Pipe_buf

If The pipe is full and then write (2) fails, with errno set to Eagain (which is also not a character write pipeline at this time).

Otherwise, from 1 to n bytes is written (i.e., a "partial write" may occur;

The caller should check the return value from write (2) to see how many bytes were actually written),

And these bytes is interleaved with the writes by other processes.

/** Verify: The Pipe_buf of the known pipeline is 4K, we start two process A, B to the pipeline each write 68K content, then we use 4 K as a group, the last byte of the pipeline to view the content, run the program several times, you will find that 68K of data will have cross-write situation **/int    Main () {const int TEST_BUF = 68 * 1024;//sets the amount of data written to 68K Char Bufa[test_buf];    Char Bufb[test_buf];    memset (Bufa, ' A ', sizeof (BUFA));    memset (BUFB, ' B ', sizeof (BUFB));    int pipefd[2];    if (pipe (PIPEFD)! = 0) err_exit ("Pipe error");    pid_t pid;    if (PID = fork ()) = =-1) err_exit ("First fork Error");        else if (PID = = 0)//first child process A, write Bufa {close (pipefd[0]) to the pipeline;        int writebytes = write (pipefd[1], Bufa, sizeof (BUFA));  cout << "A Process" << getpid () << ", write" << writebytes << "bytes to pipe"        << Endl;    Exit (exit_success);    } if (pid = fork ()) = =-1) err_exit ("Second fork Error");        else if (PID = = 0)//second child process B, write BUFB {close (pipefd[0]) to the pipeline;        int writebytes = write (pipefd[1], BUFB, sizeof (BUFB)); cout << "B Process" << getpid () << ", write" << writebytes << "bytes to pipe" << Endl;    Exit (exit_success);    }//Parent process close (pipefd[1]);   Sleep (2); Wait for two sub-processes to finish writing char buf[4 * 1024]; Apply for a 4K buf int fd = open ("Save.txt", o_wronly| o_trunc|    O_creat, 0666);    if (fd = =-1) err_exit ("File open error");        while (true) {int readbytes = read (Pipefd[0], buf, sizeof (BUF));        if (readbytes = = 0) break;        if (Write (FD, buf, readbytes) = =-1) err_exit ("Write file Error"); cout << "Parent Process" << getpid () << "read" << readbytes << "bytes from P    Ipe, buf[4095] = "<< buf[4095] << Endl; }}


Attached-Pipeline capacity query

Man 7 pipe

Note: The capacity of the pipe is not necessarily equal to pipe_buf, such as in Ubuntu, the pipe capacity is 64K, and Pipe_buf is 4K.

Linux IPC Practice (2)--Anonymous pipe

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.