C
IPC and sync
Write IPC and synchronization with pipe and semaphore.
IPC and sync
In this lesson you'll define the ipc_setup function. It creates a two-ended channel with pipe, opens a child process with fork. The child writes "ipc" with write; the parent reads it with read.
Steps: int p[2]; pipe(p);, pid_t pid = fork();, if child close(p[0]), write(p[1], "ipc", 3), close(p[1]), _exit(0). Parent: close(p[1]), read(p[0], buf, 3), close(p[0]), wait(NULL). This pattern is the basis of inter-process communication. wait synchronizes the child's completion.
Pipe flow
pipe(p) gives two descriptors: p[0] is the read end, p[1] the write end. The child uses the write end and closes the read end. The parent does the opposite.
Child: close(p[0]); write(p[1], "ipc", 3); close(p[1]); _exit(0);. Parent: close(p[1]); char buf[8] = {0}; int n = read(p[0], buf, 3); close(p[0]); wait(NULL); return n > 0 ? 1 : 0;. read blocks; it waits until the child writes. wait(NULL) reaps the child. In main add int r = ipc_setup(); and printf("ipc: %d\n", r);. The output gains "ipc: 1".
Exercise Add ipc_setup
Write int ipc_setup(void): int p[2]; pipe(p);, pid_t pid = fork();, if child close(p[0]); write(p[1], "ipc", 3); close(p[1]); _exit(0);, parent close(p[1]); char buf[8] = {0}; int n = read(p[0], buf, 3); close(p[0]); wait(NULL); return n > 0 ? 1 : 0;. Add int r = ipc_setup(); and printf("ipc: %d\n", r); to main.
Show example solution
#include <stdio.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
int worker_init(void);
int server_setup(void);
int ipc_setup(void);
int worker_count = 0;
pthread_mutex_t worker_lock = PTHREAD_MUTEX_INITIALIZER;
void *worker_fn(void *arg) {
(void)arg;
pthread_mutex_lock(&worker_lock);
worker_count++;
pthread_mutex_unlock(&worker_lock);
return NULL;
}
int worker_init(void) {
pthread_t t;
pthread_create(&t, NULL, worker_fn, NULL);
pthread_join(t, NULL);
return 1;
}
int server_setup(void) {
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un addr;
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, "/tmp/cb_p.sock", sizeof(addr.sun_path) - 1);
unlink("/tmp/cb_p.sock");
bind(fd, (struct sockaddr *)&addr, sizeof(addr));
listen(fd, 1);
return fd;
}
int ipc_setup(void) {
int p[2];
pipe(p);
pid_t pid = fork();
if (pid == 0) {
close(p[0]);
write(p[1], "ipc", 3);
close(p[1]);
_exit(0);
}
close(p[1]);
char buf[8] = {0};
int n = read(p[0], buf, 3);
close(p[0]);
wait(NULL);
return n > 0 ? 1 : 0;
}
int main(void) {
printf("Proje hazır\n");
worker_init();
printf("sayaç: %d\n", worker_count);
int sfd = server_setup();
printf("soket: %d\n", sfd >= 0 ? 1 : 0);
int r = ipc_setup();
printf("ipc: %d\n", r);
return 0;
}
Test yourself
-
What does fork return on success?
- Always 0
- 0 to child, PID to parent
- Nothing
- Always -1
Show answer
0 to child, PID to parent — fork returns 0 to the child and the child PID to the parent.
-
Match IPC steps
- pipe
- Create channel
- fork
- Child process
- write
- Send data
- wait
- Wait child
-
child branch
pid_t pid = fork(); if (pid == ____) { close(p[0]); write(p[1], "ipc", 3); _exit(0); }
Show answer
pid_t pid = fork(); if (pid == 0) { close(p[0]); write(p[1], "ipc", 3); _exit(0); }
Next lesson: Putting it together