After I carefully read the manual(i.e. man 2 pipe
), I found a demo code snippet:
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int
main(int argc, char *argv[])
{
int pipefd[2];
pid_t cpid;
char buf;
if (argc != 2) {
fprintf(stderr, "Usage: %s <string>\n", argv[0]);
exit(EXIT_FAILURE);
}
if (pipe(pipefd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
cpid = fork();
if (cpid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0) { /* Child reads from pipe */
close(pipefd[1]); /* Close unused write end */
while (read(pipefd[0], &buf, 1) > 0)
write(STDOUT_FILENO, &buf, 1);
write(STDOUT_FILENO, "\n", 1);
close(pipefd[0]);
_exit(EXIT_SUCCESS);
} else { /* Parent writes argv[1] to pipe */
close(pipefd[0]); /* Close unused read end */
write(pipefd[1], argv[1], strlen(argv[1]));
close(pipefd[1]); /* Reader will see EOF */
wait(NULL); /* Wait for child */
exit(EXIT_SUCCESS);
}
}
I made some small modifications to the code snippet above(i.e.: adding sleep
in the parent process & printing out the size returned by read
in the child process).
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <string>
#include <thread>
#include <array>
#include <iostream>
int
main(int argc, char *argv[])
{
int pipefd[2];
pid_t cpid;
std::array<char, 1024> buf;
if (pipe(pipefd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
cpid = fork();
if (cpid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0) { /* Child reads from pipe */
close(pipefd[1]); /* Close unused write end */
int size;
while (size = read(pipefd[0], buf.data(), 1) > 0)
std::cout << size << std::endl;
write(STDOUT_FILENO, "\n", 1);
close(pipefd[0]);
_exit(EXIT_SUCCESS);
} else { /* Parent writes argv[1] to pipe */
close(pipefd[0]); /* Close unused read end */
std::string str{"hello world\n"};
write(pipefd[1], str.c_str(), str.size());
std::this_thread::sleep_for(std::chrono::seconds(5));
close(pipefd[1]); /* Reader will see EOF */
wait(NULL); /* Wait for child */
exit(EXIT_SUCCESS);
}
}
Here is the output of the code snippet above:
1
1
1
1
1
1
1
1
1
1
1
1
It seems all right so far. What makes confused is that when I increase the number of bytes to read.The output is very strange.Here is the said code snippet:
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <string>
#include <thread>
#include <array>
#include <iostream>
int
main(int argc, char *argv[])
{
int pipefd[2];
pid_t cpid;
std::array<char, 1024> buf;
if (pipe(pipefd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
cpid = fork();
if (cpid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0) { /* Child reads from pipe */
close(pipefd[1]); /* Close unused write end */
int size;
while (size = read(pipefd[0], buf.data(), buf.size()) > 0)
std::cout << size << std::endl;
write(STDOUT_FILENO, "\n", 1);
close(pipefd[0]);
_exit(EXIT_SUCCESS);
} else { /* Parent writes argv[1] to pipe */
close(pipefd[0]); /* Close unused read end */
std::string str{"hello world\n"};
write(pipefd[1], str.c_str(), str.size());
std::this_thread::sleep_for(std::chrono::seconds(5));
close(pipefd[1]); /* Reader will see EOF */
wait(NULL); /* Wait for child */
exit(EXIT_SUCCESS);
}
}
Here is the strange output:
1
//new line, and no more output indeed.
Maybe I need to know which types of buffering the file descriptors returned by pipe
use.And I can't find any useful information on manual(i.e. man 2 pipe
).
Could anybody shed some light on this matter?
CodePudding user response:
>
has a higher operator precedence than =
. Thus,
size = read(pipefd[0], buf.data(), buf.size()) > 0
is equivalent to
size = (read(pipefd[0], buf.data(), buf.size()) > 0)
The first iteration would appear to consume all the data, thus read
should return 12
. 12 > 0
is true
, and true
is implicitly converted to the integer value 1
.
The next iteration, read
should return a non-positive number, ending the loop.
When the read
size was 1
, its expected return value was indistinguishable from the result of 1 > 0
.
Place the parenthesis around the assignment.
(size = read(pipefd[0], buf.data(), buf.size())) > 0