Skip to content

Instantly share code, notes, and snippets.

@aspyct
Created July 15, 2012 22:00
  • Star 11 You must be signed in to star a gist
  • Fork 7 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save aspyct/3118858 to your computer and use it in GitHub Desktop.
Unix semaphore with the C programming language, tested under Debian
#ifndef _COMMON_H_
#define _COMMON_H_
#define SEM_KEY_FILE ("sem.key")
#endif /* _COMMON_H_ */
/**
* Compile this file as "sem_client" for the pair of programs to work properly
* (view the info on sem_server.c on how to run this)
*
* gcc -o sem_client sem_client.c -Wall -Werror
*
* This is needed because the server does an `exec` of this program
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/sem.h>
#include <fcntl.h>
#include <unistd.h>
#include "common.h"
int main(int argc, char *argv[]) {
int sem_fd;
key_t sem_key;
int sem_id;
int i;
struct sembuf sop;
// Recover the sem_key from file
sem_fd = open(SEM_KEY_FILE, O_RDONLY);
if (sem_fd < 0) {
perror("Could not open sem key for reading");
exit(1);
}
// Technically speaking, the read could read less than sizeof(key_t)
// Which would be wrong.
// But in our case, it is not likely to happen...
if (read(sem_fd, &sem_key, sizeof(key_t)) != sizeof(key_t)) {
perror("Error reading the semaphore key");
exit(2);
}
// Done getting the semaphore key
close(sem_fd);
// Now obtain the (hopefully) existing sem
sem_id = semget(sem_key, 0, 0);
if (sem_id < 0) {
perror("Could not obtain semaphore");
exit(3);
}
for (i = 0; i < 5; ++i) {
sop.sem_num = 0;
sop.sem_op = -1;
sop.sem_flg = SEM_UNDO;
printf("Client #%d waiting\n", getpid());
semop(sem_id, &sop, 1);
printf("Client #%d acquired. Sleeping\n", getpid());
sleep(1);
printf("Client #%d releasing\n", getpid());
sop.sem_op = 1;
semop(sem_id, &sop, 1);
}
exit(0);
}
/**
* Run these files:
*
* $ gcc -o sem_server sem_server.c
* $ gcc -o sem_client sem_client.c
* $ ./sem_server
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <fcntl.h>
#include <sys/sem.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <errno.h>
#include "common.h"
#define CLIENT_PATH_BUFSIZE 255
int main(int argc, char *argv[]) {
key_t sem_key;
int sem_id;
int sem_fd;
char client_exe[CLIENT_PATH_BUFSIZE];
int dir_len;
int i;
struct sembuf sop;
int pid;
int status;
sem_key = ftok("./sem_server.c", 42);
// Write the key to a file for children to pick it up
sem_fd = open(SEM_KEY_FILE, O_WRONLY | O_TRUNC | O_EXCL | O_CREAT, 0644);
if (sem_fd < 0) {
perror("Could not open sem.key");
exit(1);
}
// Actual write of the key
if (write(sem_fd, &sem_key, sizeof(key_t)) < 0) {
perror("Could not write key to file");
exit(2);
}
// Done with the key
close(sem_fd);
// Create the semaphore
sem_id = semget(sem_key, 1, IPC_CREAT | IPC_EXCL | 0600);
if (sem_id < 0) {
perror("Could not create sem");
unlink(SEM_KEY_FILE);
exit(3);
}
if (semctl(sem_id, 0, SETVAL, 0) < 0) {
perror("Could not set value of semaphore");
exit(4);
}
// Now create some clients
// First create the path to the client exec
getcwd(client_exe, CLIENT_PATH_BUFSIZE);
dir_len = strlen(client_exe);
strcpy(client_exe + dir_len, "/sem_client");
printf("%s\n", client_exe);
for (i = 0; i < 5; ++i) {
if ((pid = fork()) < 0) {
perror("Could not fork, please create clients manually");
}
else if (pid == 0) {
// We're in the child process, start a client
execl(client_exe, "sem_client", (char*)0);
_exit(127);
}
}
printf("Done creating clients, sleeping for a while\n");
sleep(5);
printf("Increasing sem count\n");
sop.sem_num = 0;
sop.sem_op = 1;
sop.sem_flg = 0;
if (semop(sem_id, &sop, 1)) {
perror("Could not increment semaphore");
exit(5);
}
// Wait for all children to finish
for (;;) {
// Remove the zombie process, and get the pid and return code
pid = wait(&status);
if (pid < 0) {
if (errno == ECHILD) {
printf("All children have exited\n");
break;
}
else {
perror("Could not wait");
}
}
else {
printf("Child %d exited with status %d\n", pid, status);
}
}
// Delete semaphore and file
if (unlink(SEM_KEY_FILE) < 0) {
perror("Could not unlink key file");
}
if (semctl(sem_id, 0, IPC_RMID) < 0) {
perror("Could not delete semaphore");
}
exit(0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment