Definition
pipe(C)#include <unistd.h> int pipe(int pipefd[2]);
pipe()creates a pipe, a unidirectional data channel that can be used for inter-process communication. The arraypipefdis used to return two file descriptors referring to the ends of the pipe.pipefd[0]refers to the read end of the pipe.pipefd[1]refers to the write end of the pipe.Includes: unistd.h
Examples
Example: forksort
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
typedef struct lines {
char **lines;
int len;
int cap;
} lines_t;
void lines_append(lines_t *lines, char *str, int len) {
if (lines->len == lines->cap) {
lines->cap = (lines->cap == 0) ? 1 : lines->cap * 2;
lines->lines = realloc(lines->lines, lines->cap * sizeof(char *));
}
lines->lines[lines->len] = strdup(str);
lines->len++;
}
void lines_free(lines_t *lines) {
for (int i = 0; i < lines->len; i++) {
free(lines->lines[i]);
}
free(lines->lines);
}
typedef struct process_data {
pid_t pid;
int to_child[2]; // parent writes to [1], child reads from [0]
int from_child[2]; // child writes to [1], parent reads from [0]
} process_data_t;
bool spawn(process_data_t *ptr) {
process_data_t created = {0};
if (pipe(created.from_child) == -1 || pipe(created.to_child) == -1) {
return false;
}
created.pid = fork();
if (created.pid == -1) {
return false;
}
if (created.pid == 0) {
// inside child
dup2(created.to_child[0], STDIN_FILENO); // redirect stdin
dup2(created.from_child[1], STDOUT_FILENO); // redirect stdout
// process now uses stdin/out => can close pipe channels
close(created.to_child[0]);
close(created.to_child[1]);
close(created.from_child[0]);
close(created.from_child[1]);
execlp("./forksort", "forksort", NULL);
exit(EXIT_FAILURE);
return false;
} else {
// inside parent
close(created.to_child[0]); // parent doesn't read from child's stdin
close(created.from_child[1]); // parent doesn't write to child's stdout
}
*ptr = created;
return true;
}
int main(int argc, char *argv[]) {
if (argc > 1) {
fprintf(stderr, "Usage: %s\n", argv[0]);
return EXIT_FAILURE;
}
lines_t lines = {0};
char *line = NULL;
size_t len = 0;
ssize_t read;
while ((read = getline(&line, &len, stdin)) != -1) {
lines_append(&lines, line, (int)read);
}
free(line);
if (lines.len == 0) {
lines_free(&lines);
return EXIT_SUCCESS;
}
if (lines.len == 1) {
fputs(lines.lines[0], stdout);
lines_free(&lines);
return EXIT_SUCCESS;
}
process_data_t child1, child2;
if (!spawn(&child1) || !spawn(&child2)) {
fprintf(stderr, "%s: failed to spawn children\n", argv[0]);
lines_free(&lines);
return EXIT_FAILURE;
}
// split and write to children
FILE *out1 = fdopen(child1.to_child[1], "w");
FILE *out2 = fdopen(child2.to_child[1], "w");
if (out1 == NULL || out2 == NULL) {
fprintf(stderr, "%s: fdopen failed\n", argv[0]);
lines_free(&lines);
return EXIT_FAILURE;
}
int split = lines.len / 2;
for (int i = 0; i < split; i++) {
fputs(lines.lines[i], out1);
}
for (int i = split; i < lines.len; i++) {
fputs(lines.lines[i], out2);
}
fclose(out1);
fclose(out2);
// read and merge from children
FILE *in1 = fdopen(child1.from_child[0], "r");
FILE *in2 = fdopen(child2.from_child[0], "r");
if (in1 == NULL || in2 == NULL) {
fprintf(stderr, "%s: fdopen failed\n", argv[0]);
lines_free(&lines);
return EXIT_FAILURE;
}
char *l1 = NULL, *l2 = NULL;
size_t n1 = 0, n2 = 0;
ssize_t r1 = getline(&l1, &n1, in1);
ssize_t r2 = getline(&l2, &n2, in2);
while (r1 != -1 && r2 != -1) {
if (strcmp(l1, l2) <= 0) {
fputs(l1, stdout);
r1 = getline(&l1, &n1, in1);
} else {
fputs(l2, stdout);
r2 = getline(&l2, &n2, in2);
}
}
while (r1 != -1) {
fputs(l1, stdout);
r1 = getline(&l1, &n1, in1);
}
while (r2 != -1) {
fputs(l2, stdout);
r2 = getline(&l2, &n2, in2);
}
// cleanup
free(l1);
free(l2);
fclose(in1);
fclose(in2);
int status1, status2;
if (waitpid(child1.pid, &status1, 0) == -1 ||
waitpid(child2.pid, &status2, 0) == -1) {
fprintf(stderr, "%s: waitpid failed\n", argv[0]);
lines_free(&lines);
return EXIT_FAILURE;
}
lines_free(&lines);
if (!WIFEXITED(status1) || WEXITSTATUS(status1) != EXIT_SUCCESS ||
!WIFEXITED(status2) || WEXITSTATUS(status2) != EXIT_SUCCESS) {
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}