/* A program derived from Robbins and Robbins ch12, ch14, and ch15 examples */
/* See http://vip.cs.utsa.edu/usp/programs.html and R&R book */
/* Shows use of POSIX semaphores to provide mutex between child processes */
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/shm.h>
#include <sys/stat.h>
/* Without use of shared memory, the semaphore doesn't work across
processes! Of course it would work with threads in one process,
since they share the process address space. */
/* uncomment the next line to start using shared memory for sem_t object */
/*#define USE_SHARED_MEMORY */
#define MAXPIDS 10
void worker(int i, void * args);
int main(int argc, char *argv[]) {
int error;
int i;
int id, n;
sem_t *semlock;
pid_t pids[MAXPIDS];
if (argc != 2){ /* check for valid number of command-line arguments */
fprintf (stderr, "Usage: %s numprocesses\n", argv[0]);
return 1;
}
n = atoi(argv[1]);
if (n > MAXPIDS)
return 1;
#ifdef USE_SHARED_MEMORY
if ((id = shmget(IPC_PRIVATE, sizeof(sem_t), (S_IRUSR|S_IWUSR))) == -1) {
perror("Failed to create shared memory segment");
return 1;
}
if ((semlock = (sem_t *)shmat(id, NULL, 0)) == (void *)-1) {
perror("Failed to attach memory segment");
return 1;
}
#else
/* try using ordinary process-private memory for sem_t variable */
semlock = (sem_t *)malloc(sizeof(sem_t));
#endif
if (sem_init(semlock, 1/*shared across processes*/, 1) == -1) {
perror("Failed to initialize semaphore");
} else {
for (i = 0; i < n; i++) {
if ((pids[i] = fork()) < 0) {
fprintf(stderr, "Failed to create process:%s\n",
strerror(error));
return 1;
}
if (pids[i] == 0) { /* child */
worker(i, semlock);
exit(0);
}
}
/* here in parent of all */
for (i = 0; i < n; i++)
wait(0);
fprintf(stderr, "workers all done\n");
}
#ifdef USE_SHARED_MEMORY
if (shmdt((void *)semlock) == -1) { /* shared memory detach */
perror("Failed to destroy shared memory segment");
return 1;
}
#else
free(semlock);
#endif
return 0;
}
sf06.cs.umb.edu$ more semexworker.c
#include <errno.h>
#include <semaphore.h>
#include <stdio.h>
#include <unistd.h>
#define TEN_MILLION 10000000L
#define BUFSIZE 1024
void worker(int i, void * args)
{
char buffer[BUFSIZE];
char *c;
sem_t *semlockp;
struct timespec sleeptime;
semlockp = (sem_t *)args;
sleeptime.tv_sec = 0;
sleeptime.tv_nsec = TEN_MILLION;
snprintf(buffer, BUFSIZE, "This is process %ld\n",
(long)getpid());
c = buffer;
setbuf(stderr, NULL); // specify no buffering for stderr
/****************** entry section *******************************/
while (sem_wait(semlockp) == -1) /* Entry section */
if(errno != EINTR) {
fprintf(stderr, "Thread failed to lock semaphore\n");
return;
}
/****************** start of critical section *******************/
while (*c != '\0') {
fputc(*c, stderr); // no buffering: output each synchronously
c++;
nanosleep(&sleeptime, NULL);
}
/****************** exit section ********************************/
if (sem_post(semlockp) == -1) /* Exit section */
fprintf(stderr, "Thread failed to unlock semaphore\n");
/****************** remainder section ***************************/
return;
}
Compile and load with realtime library –lrt:
sf06.cs.umb.edu$ gcc semex.c semexworker.c -lrt
sf06.cs.umb.edu$ a.out
Run without shared memory: no process coordination
Usage: a.out numprocesses
sf06.cs.umb.edu$ a.out 4
sf06.cs.umb.edu$ a.out 4
TTTThhhhiiiissss iiiissss pppprrrroooocccceeeessssssss 6666333388897890
workers all done
After editing in #define SHARED_MEMORY to use shared memory: mutex effect, processes run one at a time in the critical section
sf06.cs.umb.edu$ a.out 4
This is process 28368
This is process 28369
This is process 28370
This is process 28371
workers all done
sf06.cs.umb.edu$