/*
* semaphore.c
*
*
* Created by Mij <mij@bitchx.it> on 12/03/05.
* Original source file available at http://mij.oltrelinux.com/devel/unixprg/
*
*/
#define _POSIX_SOURCE
#include <stdio.h>
/* sleep() */
#include <errno.h>
#include <unistd.h>
/* abort() and random stuff */
#include <stdlib.h>
/* time() */
#include <time.h>
#include <signal.h>
#include <pthread.h>
#include <semaphore.h>
/* this skips program termination when receiving signals */
void signal_handler(int type);
/*
* thread A is synchronous. When it needs to enter its
* critical section, it can't do anything other than waiting.
*/
void *thread_a(void *);
/*
* thread B is asynchronous. When it tries to enter its
* critical section, it switches back to other tasks if
* it hasn't this availability.
*/
void *thread_b(void *);
/* the semaphore */
sem_t mysem;
int main(int argc, char *argv[])
{
pthread_t mytr_a, mytr_b;
int ret;
srand(time(NULL));
signal(SIGHUP, signal_handler);
signal(SIGUSR1, signal_handler);
/*
* creating the unnamed, local semaphore, and initialize it with
* value 1 (max concurrency 1)
*/
ret = sem_init(&mysem, 0, 1);
if (ret != 0) {
/* error. errno has been set */
perror("Unable to initialize the semaphore");
abort();
}
/* creating the first thread (A) */
ret = pthread_create(&mytr_a, NULL, thread_a, NULL);
if (ret != 0) {
perror("Unable to create thread");
abort();
}
/* creating the second thread (B) */
ret = pthread_create(&mytr_b, NULL, thread_b, NULL);
if (ret != 0) {
perror("Unable to create thread");
abort();
}
/* waiting for thread_a to finish */
ret = pthread_join(mytr_a, (void *)NULL);
if (ret != 0) {
perror("Error in pthread_join");
abort();
}
/* waiting for thread_b to finish */
ret = pthread_join(mytr_b, NULL);
if (ret != 0) {
perror("Error in pthread_join");
abort();
}
return 0;
}
void *thread_a(void *x)
{
unsigned int i, num;
int ret;
printf(" -- thread A -- starting\n");
num = ((unsigned int)rand() % 40);
/* this does (do_normal_stuff, do_critical_stuff) n times */
for (i = 0; i < num; i++) {
/* do normal stuff */
sleep(3 + (rand() % 5));
/* need to enter critical section */
printf(" -- thread A -- waiting to enter critical section\n");
/* looping until the lock is acquired */
do {
ret = sem_wait(&mysem);
if (ret != 0) {
/* the lock wasn't acquired */
if (errno != EINVAL) {
perror(" -- thread A -- Error in sem_wait. terminating -> ");
pthread_exit(NULL);
} else {
/* sem_wait() has been interrupted by a signal: looping again */
printf(" -- thread A -- sem_wait interrupted. Trying again for the lock...\n");
}
}
} while (ret != 0);
printf(" -- thread A -- lock acquired. Enter critical section\n");
/* CRITICAL SECTION */
sleep(rand() % 2);
/* done, now unlocking the semaphore */
printf(" -- thread A -- leaving critical section\n");
ret = sem_post(&mysem);
if (ret != 0) {
perror(" -- thread A -- Error in sem_post");
pthread_exit(NULL);
}
}
printf(" -- thread A -- closing up\n");
pthread_exit(NULL);
}
void *thread_b(void *x)
{
unsigned int i, num;
int ret;
printf(" -- thread B -- starting\n");
num = ((unsigned int)rand() % 100);
/* this does (do_normal_stuff, do_critical_stuff) n times */
for (i = 0; i < num; i++) {
/* do normal stuff */
sleep(3 + (rand() % 5));
/* wants to enter the critical section */
ret = sem_trywait(&mysem);
if (ret != 0) {
/* either an error happened, or the semaphore is locked */
if (errno != EAGAIN) {
/* an event different from "the semaphore was locked" happened */
perror(" -- thread B -- error in sem_trywait. terminating -> ");
pthread_exit(NULL);
}
printf(" -- thread B -- cannot enter critical section: semaphore locked\n");
} else {
/* CRITICAL SECTION */
printf(" -- thread B -- enter critical section\n");
sleep(rand() % 10);
/* done, now unlocking the semaphore */
printf(" -- thread B -- leaving critical section\n");
sem_post(&mysem);
}
}
printf(" -- thread B -- closing up\n");
/* joining main() */
pthread_exit(NULL);
}
void signal_handler(int type)
{
/* do nothing */
printf("process got signal %d\n", type);
return;
}