Parent directory Makefile connect2.c counter.c
Download
CC=gcc CFLAGS=-g -Wall LDFLAGS=-pthread executables = connect2 counter objects = connect2.o counter.o .PHONY: default default: $(executables) $(executables): $(objects): .PHONY: clean clean: rm -f *~ *.out $(objects) $(executables) .PHONY: all all: clean default
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/wait.h> ////////////////////////////////////////////////////////////////////// int main(int argc, char **argv) { int fd[2]; pid_t pid1, pid2; // Split arguments ["cmd1", ..., "--", "cmd2", ...] into // ["cmd1", ...] and ["cmd2", ...] char **argv1 = argv + 1; // argv for the first command char **argv2; // argv for the second command for (argv2 = argv1; *argv2; argv2++) { if (strcmp(*argv2, "--") == 0) { *argv2++ = NULL; break; } } if (*argv1 == NULL || *argv2 == NULL) { fprintf(stderr, "%s\n", "separate two commands with --"); exit(1); } ////////////////////////////////////////////////////////////////////// #ifdef DEBUG1 fprintf(stderr, "%s", "argv1: "); while (*argv1) fprintf(stderr, "%s ", *argv1++); fprintf(stderr, "\n%s", "argv2: "); while (*argv2) fprintf(stderr, "%s ", *argv2++); fprintf(stderr, "\n"); exit(0); #endif ////////////////////////////////////////////////////////////////////// pipe(fd); if ((pid1 = fork()) == 0) { close(fd[0]); // Close read end of pipe dup2(fd[1], 1); // Redirect stdout to write end of pipe close(fd[1]); // stdout already writes to pipe, close spare fd execvp(*argv1, argv1); // Unreachable } if ((pid2 = fork()) == 0) { close(fd[1]); // Close write end of pipe dup2(fd[0], 0); // Redirect stdin from read end of pipe close(fd[0]); // stdin already reads from pipe, close spare fd execvp(*argv2, argv2); // Unreachable } // Parent does not need either end of the pipe close(fd[0]); close(fd[1]); ////////////////////////////////////////////////////////////////////// waitpid(pid1, NULL, 0); waitpid(pid2, NULL, 0); return 0; }
#include <stdio.h> #include <unistd.h> #include <assert.h> #include <semaphore.h> #include <sys/mman.h> #include <sys/types.h> #include <sys/wait.h> #define LOOPS 1000 struct counter { sem_t sem; int cnt; }; static struct counter *counter = NULL; static void inc_loop() { for (int i = 0; i < LOOPS; i++) { sem_wait(&counter->sem); // Not an atomic operation, needs lock! // 1) Load counter->cnt into tmp // 2) Increment tmp // 3) Store tmp into counter->cnt counter->cnt++; sem_post(&counter->sem); } } int main(int argc, char **argv) { // Create a shared anonymous memory mapping, set global pointer to it counter = mmap(/*addr=*/NULL, sizeof(struct counter), // Region is readable and writable PROT_READ | PROT_WRITE, // Want to share anonymous mapping with forked child MAP_SHARED | MAP_ANON, /*fd=*/-1, // No associated file /*offset=*/0); assert(counter != MAP_FAILED); // Mapping is already zero-initialized. assert(counter->cnt == 0); sem_init(&counter->sem, /*pshared=*/1, /*value=*/1); pid_t pid; if ((pid = fork()) == 0) { inc_loop(); return 0; } inc_loop(); waitpid(pid, NULL, 0); printf("Total count: %d, Expected: %d\n", counter->cnt, LOOPS * 2); sem_destroy(&counter->sem); assert(munmap(counter, sizeof(struct counter)) == 0); return 0; }