Session 10 : Process Synchronization - Programming Continue


Process Synchronization- Programming Continue 

A Boy >>>>Its Easier To Pick Up A Girl Of Weight 45 Kg But
Its Quiet Difficult To Pick Up A Gas Cylinder Of Weight 14.2 Kg
Strange But True. FACT”

Example 1 : Mutual exclusion by means of semaphores implemented with pipe()
/*
Semaphore.c

Illustrates the
implementation of semaphores by means of
system call pipe
*/

#include <stdio.h>
#include <stdlib.h>

typedef int * semaphore;
semaphore me; // Mutual Exclusion semaphore

semaphore
make_sem()
{
int *sem;

sem = calloc(2,sizeof(int)); //allocate memory for two sem
pipe(sem); // pipe this two sempahore together
return sem;
}

void
WAIT(semaphore s)
{
int junk;

if (read(s[0], &junk, 1) <=0) { // it blocks if pipe is empty
fprintf(stderr, "ERROR : wait\n");
exit(1);
}
}

void
SIGNAL(semaphore s)
{

if (write(s[1], "x", 1) <=0) {
fprintf(stderr, "ERROR : signal\n");
exit(1);
}
}

void
process(int i)
{
for(;;) {
WAIT(me); // first it wait for the semaphore before processing
printf("Entering critical region of process %d\n", i);
sleep(2);
printf("Exiting critical region of process %d\n",i);
SIGNAL(me); // signals out
sleep(1);
}
}

int
main()
{
int i;

me = make_sem();
SIGNAL(me); //initialize to 1 the me semaphore (value 1 means semph. Is free)
SIGNAL(me);
for(i=0; i<4; i++)
if(fork() == 0)
break;
process(i);
exit(0);
}

Result:

Entering critical region of process 0 
Entering critical region of process 2 
Exiting critical region of process 0 
Entering critical region of process 3 
Exiting critical region of process 2 
Entering critical region of process 4 
Exiting critical region of process 3 
Exiting critical region of process 4 
Entering critical region of process 0 
Entering critical region of process 2 
Exiting critical region of process 0 

.............


Example 2 : Alarm clock signals 
/*
voila-alarm.c
Illustrates the use of the system calls
signal, alarm, and pause
*/
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

void catcher();
void catcher1();


int i = 1;

// "interrupt" handler
void
catcher()
{
system("date");
printf("voila'\n");
if (i == 1)
signal(SIGALRM,catcher1);// set up the alarm handler i.e. catcher
else
signal(SIGALRM,catcher);
i = 3-i;
}


void
catcher1()
{
system("date");
printf("here I'm\n");
if (i == 1)
signal(SIGALRM,catcher1);
/* SIGALRM signal is delivered by the operating system by request from the user after some amount of time,
catcher1 is the function that is called by the signal
//set up
alarm handler

 signal(SIGALRM, alarm_handler);
*/
else
signal(SIGALRM,catcher);
i = 3-i; // swap 1 and 2
}

int
main()
{
int i;
//signal() sets a function to handle a signal
signal(SIGALRM,catcher); // declaration for the kernel. It means:
// I don't want to die (default action)
// when I receive a SIGALRM signal, instead
// I will execute function "catcher"

while(1) {
alarm(5); // schedule alarm for 5 second
printf("waiting begins\n");
pause(); /*do not proceed until signal is handled
suspends program execution until a signal arrives whose action is either to execute a handler funciton, or terminate a process
*/
printf("end wait\n");
}
exit(0);
}

Result:
waiting begins 
Tue Nov 25 17:23:54 CET 2014 
voila'
end wait 
waiting begins 
Tue Nov 25 17:23:59 CET 2014 
here I'm 
end wait 
waiting begins 
Tue Nov 25 17:24:04 CET 2014 
voila'

............


Example 3 : Scheduler of processes running at fixed intervals of time.

/* SCHEDULER con SEMAFORI */
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

#define NPROC 2

typedef int *semaforo;
semaforo clock, psem[2];
int deadline[NPROC];
int intervallo[NPROC];
int tempo = 0;
int sem_array[20];
int p_sem_array = 0;

semaforo
make_sem ()
{
int *sem;

sem = &sem_array[p_sem_array];
p_sem_array++;
p_sem_array++;
pipe (sem);
// this creates a pipe, a unidirectional data channel that can be used for
// interprocess communication
return sem;
}

void
WAIT (semaforo s)
{
int junk;
/* read() function attempts to read nbytes from the file associated with the handle and places the character read into the buffer
*/
if (read (s[0], &junk, 1) <= 0)
{
fprintf (stderr, "ERRORE : WAIT\n");
exit (1);
}
}

void
SIGNAL (semaforo s)
{

/* write() function attempts to write nbytes from buffer to the file associated with the handle.
*/
if (write (s[1], "s", 1) <= 0)
{
fprintf (stderr, "ERRORE : signal\n");
exit (1);
}
}

void
proc0 ()
{
int i;

while (1)
{
WAIT (psem[0]);
i = getpid ();
printf ("I am process : %d", i);
system ("date");
}
}

void
proc1 ()
{
int i;

while (1)
{
WAIT (psem[1]);
i = getpid ();
printf ("I am process : %d", i);
system ("date");
}
}

void
catcher ()
{
printf ("tick\n");
SIGNAL (clock);
signal (SIGALRM, catcher); // set the singal handler
}

void
sveglia ()
{
signal (SIGALRM, catcher);
while (1)
{
alarm (1); // set alarm for 1 sec
pause (); // do not proceed until the signal is handled
}
}


int
main ()
{
int i;


clock = make_sem ();
psem[0] = make_sem ();
psem[1] = make_sem ();

/* Inizializza scheduler */
intervallo[0] = 5;
intervallo[1] = 7;
deadline[0] = 5;
deadline[1] = 7;

if ((i = fork ()) == 0)
proc0 ();
if (fork () == 0)
proc1 ();
if (fork () == 0)
sveglia ();

/* controllo schedulazione */

while (1)
{
WAIT (clock);
tempo++;
for (i = 0; i < NPROC; i++)
{

if (deadline[i] <= tempo)
{
deadline[i] = tempo + intervallo[i];
printf ("Wakeup the process : %d at time %d\n", i, tempo);
SIGNAL (psem[i]);
}
}


}
}



Result:
tick

tick

tick

tick

tick

Wakeup the process: 0 at time: 5 
Tue Nov 25 20:22:48 CET 2014 
tick

tick

Wakeup the process: 1 at time: 7 
Tue Nov 25 20:22:50 CET 2014 
tick

tick

tick

Wakeup the process: 0 at time: 10 
Tue Nov 25 20:22:53 CET 2014 

Q?What are POSIX semaphores
/>this semaphores allows processes and threads to synchronize their
actions
 
 
Synchronization Examples of UNIX Threads
Example 1 : Mutual Exclusion by means of mutex 
/*
* mutex.c
* Illustrates the use of mutex
* for mutual exclusion
*/
#include <pthread.h>
#include "errors.h"
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void *ME_thread (void *arg)
{
int status;
/*
* pthread_self obtain the ID of the calling thread
* pthread_detach() detach a thread
* Pthread_mutex_lock() locks the mutex object referenced by mutex
*/
status = pthread_detach (pthread_self ());
if (status != 0)
err_abort (status, "Detach thread");
for(;;) {
status = pthread_mutex_lock (&mutex);
if (status != 0) err_abort (status, "Lock mutex");
printf("critical region of thread %ld\n", pthread_self());

status = pthread_mutex_unlock (&mutex);
if (status != 0) err_abort (status, "Lock mutex");
sleep(2);
// sched_yield(); // rilascia volontariamente il processore
}
return NULL;
}
int main (int argc, char *argv[])
{
int status;
pthread_t thread;

// setvbuf (stdout, NULL, _IONBF, 0);
setbuf(stdout,0); // no buffering for stdout
/*
* pthread_create() creates a new thread
* pthread_exit() does the thread termination
*/
status = pthread_create (&thread, NULL, ME_thread, NULL);
if (status != 0)
err_abort (status, "Create print thread");

status = pthread_create (&thread, NULL, ME_thread, NULL);
if (status != 0)
err_abort (status, "Create print thread");

pthread_exit(NULL);
}


Result:
critical region of thread  -1219318976 
critical region of thread  -1227711680 
critical region of thread  -1219318976 
critical region of thread  -1227711680 
critical region of thread  -1219318976 
...


Example: 2 Mutual Exclusion with Mutex testing 
/*
* trylock.c
*
* Demonstrate a simple use of pthread_mutex_trylock. The
* counter_thread updates a shared counter at intervals, and a
* monitor_thread occasionally reports the current value of the
* counter -- but only if the mutex is not already locked by
* counter_thread.
*
* Special notes: On a Solaris system, call thr_setconcurrency()
* to allow interleaved thread execution, since threads are not
* timesliced.
*/

/*
* pthread_mutex_trylock just try to lock mutex
*/
#include <pthread.h>
#include "errors.h"

#define SPIN 10000000

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
/*
* pthread_mutex_t are the types of variables that can be initialized statically
* using the constants PTHREAD_MUTEX_INITIALIZER (for fast mutexes )
*/
long counter;
time_t end_time;

/*
* Thread start routine that repeatedly locks a mutex and
* increments a counter.
*/
void *counter_thread (void *arg)
{
int status;
int spin;

/*
* Until end_time, increment the counter each
* second. Instead of just incrementing the counter, it
* sleeps for another second with the mutex locked, to give
* monitor_thread a reasonable chance of running.
*/
while (time (NULL) < end_time)
{
status = pthread_mutex_lock (&mutex);
if (status != 0)
err_abort (status, "Lock mutex");
for (spin = 0; spin < SPIN; spin++)
counter++;
status = pthread_mutex_unlock (&mutex);
if (status != 0)
err_abort (status, "Unlock mutex");
sleep (1);
}
printf ("Counter is %#lx\n", counter);
return NULL;
}

/*
* Thread start routine to "monitor" the counter. Every 3
* seconds, try to lock the mutex and read the counter. If the
* trylock fails, skip this cycle.
*/
void *monitor_thread (void *arg)
{
int status;
int misses = 0;


/*
* Loop until end_time, checking the counter every 3
* seconds.
*/
while (time (NULL) < end_time)
{
sleep (3);
status = pthread_mutex_trylock (&mutex);
if (status != EBUSY)
{
if (status != 0)
err_abort (status, "Trylock mutex");
printf ("Counter is %ld\n", counter/SPIN);
status = pthread_mutex_unlock (&mutex);
if (status != 0)
err_abort (status, "Unlock mutex");
} else {
misses++; /* Count "misses" on the lock */
printf ("Monitor thread miss update.\n");
}
}
printf ("Monitor thread missed update %d times.\n", misses);
return NULL;
}

int main (int argc, char *argv[])
{
int status;
pthread_t counter_thread_id;
pthread_t monitor_thread_id;

#ifdef sun
/*
* On Solaris 2.5, threads are not timesliced. To ensure
* that our threads can run concurrently, we need to
* increase the concurrency level to 2.
*/
DPRINTF (("Setting concurrency level to 2\n"));

/*
* dprintf – print to a file descriptor
* file descriptor is the abstract indicator to access the file
*/
thr_setconcurrency (2);
#endif

end_time = time (NULL) + 60; /* Run for 1 minute */
status = pthread_create (
&counter_thread_id, NULL, counter_thread, NULL);
if (status != 0)
err_abort (status, "Create counter thread");
status = pthread_create (
&monitor_thread_id, NULL, monitor_thread, NULL);
if (status != 0)
err_abort (status, "Create monitor thread");
status = pthread_join (counter_thread_id, NULL);
if (status != 0)
err_abort (status, "Join counter thread");
status = pthread_join (monitor_thread_id, NULL);
if (status != 0)
err_abort (status, "Join monitor thread");
return 0;
}

Result:

Counter is 3 
Counter is 6 
Counter is 9 
Counter is 12 
Counter is 15 
Counter is 18 
Counter is 21 
Counter is 24 
Counter is 27 
Counter is 29 
Counter is 32 
Counter is 35 
Counter is 38 
Counter is 41 
Counter is 44 
Counter is 47 
Counter is 50 
Counter is 53 
Counter is 56 
Counter is 58 
Monitor thread missed update 0 times. 
Counter is 0x22921900 


Example 3 : Event Management with condition variables 
/*
* cond.c
*
* Demonstrate a simple condition variable wait.
* Remark:
* pthread_cond_wait performs
* mutex unlock and then blocks the thread
* when the control returns to thread the mutex is locked
*/
#include <pthread.h>
#include <time.h>
#include "errors.h"

typedef struct my_struct_tag {
pthread_mutex_t mutex; /* Protects access to value */
pthread_cond_t cond; /* Signals change to value */
int value; /* Access protected by mutex */
} my_struct_t;

my_struct_t data = {
PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, 0};

int hibernation = 1; /* Default to 1 second */

/*
* Thread start routine. It will set the main thread's predicate
* and signal the condition variable.
*/
void *
wait_thread (void *arg)
{
int status;

sleep (hibernation);
status = pthread_mutex_lock (&data.mutex);
if (status != 0)
err_abort (status, "Lock mutex");
data.value = 1; /* Set predicate */
status = pthread_cond_signal (&data.cond);
if (status != 0)
err_abort (status, "Signal condition");
status = pthread_mutex_unlock (&data.mutex);
if (status != 0)
err_abort (status, "Unlock mutex");
return NULL;
}

int main (int argc, char *argv[])
{
int status;
pthread_t wait_thread_id;
struct timespec timeout;

/*
* If an argument is specified, interpret it as the number
* of seconds for wait_thread to sleep before signaling the
* condition variable. You can play with this to see the
* condition wait below time out or wake normally.
*/
if (argc > 1)
hibernation = atoi (argv[1]);

/*
* Create wait_thread.
*/
status = pthread_create (&wait_thread_id, NULL, wait_thread, NULL);
if (status != 0)
err_abort (status, "Create wait thread");

/*
* Wait on the condition variable for 2 seconds, or until
* signaled by the wait_thread. Normally, wait_thread
* should signal. If you raise "hibernation" above 2
* seconds, it will time out.
*/
timeout.tv_sec = time (NULL) + 2;
timeout.tv_nsec = 0;
status = pthread_mutex_lock (&data.mutex);
if (status != 0)
err_abort (status, "Lock mutex");

while (data.value == 0) {
status = pthread_cond_timedwait (
&data.cond, &data.mutex, &timeout);
if (status == ETIMEDOUT) {
printf ("Condition wait timed out.\n");
break;
}
else if (status != 0)
err_abort (status, "Wait on condition");
}

if (data.value != 0)
printf ("Condition was signaled.\n");
status = pthread_mutex_unlock (&data.mutex);
if (status != 0)
err_abort (status, "Unlock mutex");
return 0;
}

Result:
Condition was signaled. 


Example 4 : Producer-Consumer 

/* The classic producer-consumer example.
* Illustrates mutexes and conditions.
* All integers between 0 and 9999 should be printed exactly twice,
* once to the right of the arrow and once to the left.
*/

#include <stdio.h>
#include "pthread.h"

#define BUFFER_SIZE 16

/* Circular buffer of integers. */

struct prodcons
{
int buffer[BUFFER_SIZE]; /* the actual data */
pthread_mutex_t lock; /* mutex ensuring exclusive access to buffer */
int readpos, writepos, count; /* positions for reading and writing */
pthread_cond_t notempty; /* signaled when buffer is not empty */
pthread_cond_t notfull; /* signaled when buffer is not full */
};

/* Initialize a buffer */
static void
init (struct prodcons *b)
{
pthread_mutex_init (&b->lock, NULL);
pthread_cond_init (&b->notempty, NULL);
pthread_cond_init (&b->notfull, NULL);
b->readpos = 0;
b->writepos = 0;
b->count = 0;
}

/* Store an integer in the buffer */
static void
put (struct prodcons *b, int data)
{
pthread_mutex_lock (&b->lock);
/* Wait until buffer is not full */
while (b->count == BUFFER_SIZE)
{
pthread_cond_wait (&b->notfull, &b->lock);
/* pthread_cond_wait reacquired b->lock before returning */
}
/* Write the data and advance write pointer */
b->buffer[b->writepos] = data;
b->writepos++;
if (b->writepos >= BUFFER_SIZE)
b->writepos = 0;
b->count++;
/* Signal that the buffer is now not empty */
pthread_cond_signal (&b->notempty);
pthread_mutex_unlock (&b->lock);
}

/* Read and remove an integer from the buffer */
static int
get (struct prodcons *b)
{
int data;
pthread_mutex_lock (&b->lock);
/* Wait until buffer is not empty */
while (b->count == 0)
{
pthread_cond_wait (&b->notempty, &b->lock);
}
/* Read the data and advance read pointer */
data = b->buffer[b->readpos];
b->readpos++;
if (b->readpos >= BUFFER_SIZE)
b->readpos = 0;
b->count--;
/* Signal that the buffer is now not full */
pthread_cond_signal (&b->notfull);
pthread_mutex_unlock (&b->lock);
return data;
}

/* A test program: one thread inserts integers from 1 to 10000,
the other reads them and prints them. */

#define OVER (-1)

struct prodcons buffer;

static void *
producer (void *data)
{
int n;
for (n = 0; n < 10000; n++)
{
printf ("%d --->\n", n);
put (&buffer, n);
}
put (&buffer, OVER);
return NULL;
}

static void *
consumer (void *data)
{
int d;
while (1)
{
d = get (&buffer);
if (d == OVER)
break;
printf ("---> %d\n", d);
}
return NULL;
}

int
main (void)
{
pthread_t th_a, th_b;
void *retval;

init (&buffer);
/* Create the threads */
pthread_create (&th_a, NULL, producer, 0);
pthread_create (&th_b, NULL, consumer, 0);
/* Wait until producer and consumer finish. */
pthread_join (th_a, &retval);
pthread_join (th_b, &retval);
return 0;
}



Comments

Popular Posts