Linux inter-process communication (IPC) programming practices (I) Basic concepts and anonymous Pipelines

Source: Internet
Author: User

Linux inter-process communication (IPC) programming practices (I) Basic concepts and anonymous Pipelines

Inter-process communication can be achieved at least by sending open files. Different processes transmit information through one or more files. In fact, this method is used in many application systems. However, generally, inter-process Communication (IPC: InterProcess Communication) does not include this seemingly low-level Communication method. There are many methods to implement inter-process communication in Unix systems, and unfortunately, very few methods can be transplanted in all Unix systems (the only one is a half-duplex pipeline, this is also the most primitive communication method ). Linux, as a new operating system, supports almost all common inter-process communication methods in Unix: pipelines, message queues, shared memory, semaphores, and interfaces.

Pipeline Concept

Pipelines are the oldest form of inter-process communication in Unix. We call a data stream connecting a process to another process as a "Pipeline". The essence of pipelines is a fixed-size kernel buffer; there are two types of pipelines: An unnamed pipeline and a named pipeline. The former is used for communication between parent and child processes, and the latter is used for communication between any two processes running on the same machine.

 

MPs queue restrictions

1) pipelines are half-duplex and data can only flow in one direction. Two pipelines need to be established when both parties need to communicate;

2) an anonymous pipeline can only be used for communication between processes with common ancestor (for example, parent processes and fork child processes), Because pipe creates two file descriptors, different processes cannot be directly obtained. (generally, a pipeline is created by a process, and then the process calls fork. Then, the Parent and Child processes share the pipeline)

Create an anonymous MPs queue

 

#include 
 
    int pipe(int pipefd[2]);  
 

Parameters

Pipefd: an array of file descriptors. pipefd [0] indicates the read end, And pipefd [1] indicates the write end, as shown below:

(1) Next, we use an anonymous pipeline to communicate between parent and child processes. The child process sends information to the parent process.

 

int main(){        int pipefd[2];        if(pipe(pipefd)==-1)                ERR_EXIT("pipe error!");        pid_t pid;        pid=fork();        if(pid==-1)                ERR_EXIT("fork error");        if(pid==0)        {                close(pipefd[0]);                write(pipefd[1],"hello",5);                close(pipefd[1]);                exit(EXIT_SUCCESS);        }        close(pipefd[1]);        char buf[10]={0};        read(pipefd[0],buf,10);        printf("buf=%s\n",buf);         return 0; }
Result: the parent process receives the hello message sent by the child process.

 

(2) We can simulate the implementation of the MPs queue command ls | wc-w. The key points are:

 

1. The sub-process runs ls, dup2 (pipefd [1], STDOUT_FILENO) redirects the standard output, locates the pipeline write end, and ls writes to the pipeline write end instead of the standard output device;

2. When the parent process runs wc-w, wc obtains data from the read end of the MPs queue instead of the standard input device.

3. Send the output of sub-processes to the wc input through pipelines.

 

Int main () {int pipefd [2]; if (pipe (pipefd) =-1) ERR_EXIT ("pipe error! "); Pid_t pid; pid = fork (); if (pid =-1) ERR_EXIT (" fork error "); if (pid = 0) {dup2 (pipefd [1], STDOUT_FILENO); // redirect output close (pipefd [0]); close (pipefd [1]); execlp ("ls ", "ls", NULL); // if an error occurs, execute the following code fprintf (stderr, "error execute ls \ n"); exit (EXIT_FAILURE );} dup2 (pipefd [0], STDIN_FILENO); close (pipefd [0]); close (pipefd [1]); execlp ("wc", "wc ", "-w", NULL); fprintf (stderr, "error execute wc \ n"); exit (EXIT_FAILURE); return 0 ;}

(3) Implement cp operations

Cat commands without any parameters are read from standard input and written to standard output. 0-> Makefile; 1-> Makefile2;

 

int main(){        close(0);        open("Makefile",O_RDONLY);        close(1);        open("Makefile2",O_WRONLY | O_CREAT | O_TRUNC,0644);        execlp("cat","cat",NULL);         return 0; }
MPs queue read/write rules

 


 

We verify the above rules one by one.

(1) If the MPs queue is empty, read will be blocked (mode). If the non-blocking mode is used, that is, the fcntl function will be used to modify the mode.

 

 

 

int flags=fcntl(pipefd[0],F_SETFL,flags | O_NONBLOCK);read(pipefd[0],buf,10);

At this time, the read operation will fail, and a resource temporarily unavailable error will be displayed.

(2) When the write end of the MPs queue is closed, the read output is 0, but no error is reported, indicating that the data is read to the end of the file.

 

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;  }  
(3) If the file descriptor corresponding to the reading end of all pipelines is disabled, the write operation generates a signal SIGPIPE and the process is terminated. It will take effect if we customize the SIGPIPE processing function.

 

 

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");  }  
The singal error is printed.

 

(4) Relationship between PIPE_BUF and atomic operations,

 

The PIPE_BUF of the pipeline is known to be 4 K. We start two processes A and B to write K content to the pipeline respectively, and then we take 4 K as A group, to facilitate the viewing of the content of the last byte of the MPs queue, run the program several times and you will find that the data of the 68K will be written in parallel.

 

Int main () {const int TEST_BUF = 68*1024; // set the written data volume to 68 K char bufA [TEST_BUF]; char bufB [TEST_BUF]; memset (bufA, 'A', sizeof (bufA); memset (bufB, 'B', sizeof (bufB); int pipefd [2]; if (pipefd )! = 0) err_exit ("pipe error"); pid_t pid; if (pid = fork () =-1) err_exit ("first fork error "); else if (pid = 0) // The first sub-process A writes the 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) // The second sub-process B writes 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 the two child processes to finish writing the char buf [4*1024]; // apply for a 4 K 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 pipe, buf [4095] =" <buf [4095] <endl ;}}

Note: You can use man 7 pipe to query information about the pipeline capacity. In addition, the pipeline capacity is not necessarily equal to PIPE_BUF. For example, in Ubuntu, the pipeline capacity is 64 K, while PIPE_BUF is 4 K

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.