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
Post a Comment