Parent directory
Makefile
connect2.c
counter.c
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_ANONYMOUS,
/*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);
munmap(counter, sizeof(struct counter));
}