• No results found

Synchronization (Part 1)

N/A
N/A
Protected

Academic year: 2021

Share "Synchronization (Part 1)"

Copied!
55
0
0

Loading.... (view fulltext now)

Full text

(1)

Synchronization (Part 1)

1/55

Synchronization (Part 1)

(2)

Synchronization (Part 1)

2/55

Learning Objectives

I

Understand and solve synchronization problems in multi-threaded and multi-process programs.

I

Understand the concepts of race conditions, mutual exclusion, critical section and deadlocks

I

Explain and use synchronization primitives such as mutexes and sempahores

I

Understand the producer-consumer synchronization design pattern

I

Understand how to use basic synchronization primitives in PThreads library and Windows API

https://www.youtube.com/watch?v=k2KMnpD46jI

(3)

Synchronization (Part 1)

3/55

Interacting Processes/Threads

I

Concurrent programs is an umbrella term for

multi-threaded programs and multi-process applications.

I

Processes (Threads) can be

contending

or

cooperating.

Either way, synchronization is needed.

I Parallel and Distributed computing is now in the mainstream with multi-core and many-core systems and clusters.

I

Variety of parallel programming languages and systems are

available. Most operating systems provide native support

for multi-threaded programs and libraries are widely

available for parallel programming.

(4)

Synchronization (Part 1)

4/55

Parallelizing mergesort using threads

I Consider the standard recursive mergesort. It divides the array into two halves, sorts each half recursively and then merges them to sort the entire array. See example code at:

mergesort/single-threaded

I v o i d s e r i a l _ m e r g e s o r t (int A [] , int p , int r ) {

if ( r - p +1 <= I N S E R T I O N _ S O R T _ C U T O F F ) { i n s e r t i o n _ s o r t ( A , p , r );

} e l s e {

int q = ( p + r ) / 2 ;

s e r i a l _ m e r g e s o r t ( A , p , q );

s e r i a l _ m e r g e s o r t ( A , q +1 , r );

m e r g e ( A , p , q , r );

} }

I How would you parallelize mergesort using multiple threads?

(5)

Synchronization (Part 1)

5/55

Concurrent Processes

I

A concurrent program consists of several sequential processes whose execution sequences are

interleaved. The

sequential processes communicate with each other in order to synchronize or to exchange data.

I

Suppose a concurrent process P consists of two processes

p1

and p

2

. Then we can imagine

interleaving

as if some supernatural being were to execute the instructions one at a time, each time flipping a coin to decide whether the next one will be from p

1

or p

2

. These execution sequences exhaust the possible behaviors of P.

I

Suppose p

1

has m instructions and p

2

has n instructions.

How many possible interleavings are there?

m + n

m



(which is exponential!)

(6)

Synchronization (Part 1)

6/55

Nondeterminism, Race conditions and Critical Sections

I Race Condition.

When two or more processes are reading or writing shared data and the final result depends on the order in which their instructions get scheduled.

I Critical Section.

The section of a program where shared data is accessed. We must ensure that of all the processes accessing the same shared data only one process is in its critical section at a time. This is called the

mutual exclusion

problem.

I

We want to solve

mutual exclusion

problem without

making any assumptions on the speed of the CPU, number

of CPUs and the scheduling order of the processes.

(7)

Synchronization (Part 1)

7/55

An Example of a Race Condition

shared double balance; /* shared variable */

/* Code for process p1 */ /* Code schema for process p2 */

... ...

balance = balance + amount balance = balance - amount

... ...

/* Compiled code for p1 */ /* Compiled code for p2 */

load R1, balance load R1, balance

load R2, amount load R2, amount

add R1, R2 sub R1, R2

store R1, balance store R1, balance

I Given initialbalanceof $100, amount to credit to be $30 and amount to debit to be $80, how many possible values canbalancehave after the two processes access the shared variable?

I Code example: bad-bank-balance.cIllustratesrace conditionswhen multiple threads access the same global variable and the result depends on the interleaving of threads.

(8)

Synchronization (Part 1)

8/55

A Model Concurrent Process

for ( ; ; ) {

/* pre - p r o t o c o l */

...

/* c r i t i c a l s e c t i o n */

...

/* post - p r o t o c o l */

...

/* r e m a i n d e r */

...

}

I We assume that the process never terminates in the code for pre-protocol, critical section, post-protocol. A process can terminate abnormally in theremaindersection. If a process dies in theremaindersection, it should not affect other processes.

(9)

Synchronization (Part 1)

9/55

Properties of Concurrent Processes

I Correctness. Comes in two flavors: safety and liveness.

I Safety. If the program terminates, the answer must be “correct.”

Safety can always be improved by giving up some concurrency.

I Liveness. If something is supposed to happen, then eventually it will happen. For example:

I If a process wishes to enter its critical section, then eventually it will do so.

I If a producer produces data, then eventually the consumer will consume it.

There are two types of violations of liveness: deadlockandlockout.

I deadlock. No process is able to make any progress. The absence of deadlock can be shown by proving that there is at least one live process.

I lockoutorstarvation.There is always some process that can make progress but some identifiable process is being indefinitely delayed.

This is more difficult to discover and correct.

I Fairness.A process wishing to progress must get a fair deal relative to all other processes. No precise definition is possible.

(10)

Synchronization (Part 1)

10/55

Mutual Exclusion via Disabling Interrupts

s h a r e d d o u b l e b a l a n c e ; /* s h a r e d v a r i a b l e s */

/* P r o c e s s p1 */ /* P r o c e s s p2 */

d i s a b l e I n t e r r u p t s (); d i s a b l e I n t e r r u p t s ();

b a l a n c e = b a l a n c e + a m o u n t ; b a l a n c e = b a l a n c e - a m o u n t ; e n a b l e I n t e r r u p t s (); e n a b l e I n t e r r u p t s ();

(11)

Synchronization (Part 1)

11/55

Mutual Exclusion via Disabling Interrupts

I

A simple way to ensure mutual exclusion is to

disable interrupts. But disabling interrupts is fraught with pitfalls:

I User processes may cause havoc like not turning on the interrupts again.

I What is we have more than one CPU? Doesn’t work if the system has more than one CPUs.

I However, this technique could be useful within the kernel in a limited context. In Linux, this is known as the Big Kernel Lock (BKL).

I Note: the BKL was removed in Linux version 2.6.39 and replaced with finer grained locking.

I The git commit that removed the last traces of the BKL is here: http://git.kernel.org/cgit/linux/kernel/

git/torvalds/linux.git/commit/?id=

4ba8216cd90560bc402f52076f64d8546e8aefcb

(12)

Synchronization (Part 1)

12/55

Synchronization using Shared Memory

I

Explicitly synchronize the processes through

shared variables. The processes co-operate to ensure mutual

exclusion in the critical section. But accessing the shared variables would itself become a critical section.

I Deadlocks

can also be created while trying to ensure

mutual exclusion.

(13)

Synchronization (Part 1)

13/55

The Rules of the Game

1. A concurrent program will consist of two or more sequential programs whose execution sequences are interleaved.

2. The processes must beloosely connected. In particular, the failure of any process outside its critical section and protocols must not affect other processes.

3. A concurrent program is correct if it does not suffer from violation of safety properties such asmutual exclusionand of liveness properties such asdeadlockandlockout.

4. A concurrent program is incorrect if there exists an interleaved execution sequence which violates a correctness requirement. Hence it is sufficient to construct a scenario to show incorrectness; to show correctness requires a mathematical argument that the program is correct for all execution sequences.

5. No timing assumptions are made except that no process halts in its critical section and that, if there are ready processes, one is eventually scheduled for execution. We may impose other fairness requirements.

6. We shall assume some primitive synchronization instructions such as a memory arbiter, which guarantees that each memory access is an atomic (indivisible) operation.

(14)

Synchronization (Part 1)

14/55

The Igloo Metaphor

Only one person can enter the igloo at a time. The small size of the igloo is a metaphor for the memory arbiter. The Igloo example is borrowed from the book “Principles of concurrent programming” by M. Ben-Ari.

(15)

Synchronization (Part 1)

15/55

First Attempt

int t u r n =1; /* s h a r e d v a r i a b l e t u r n */

v o i d P1 () { for ( ; ; ) {

w h i l e ( t u r n == 2); // do n o t h i n g /* c r i t i c a l _ s e c t i o n _ 1 */

t u r n = 2;

/* r e m a i n d e r _ 1 */

} }

v o i d P2 () { for ( ; ; ) {

w h i l e ( t u r n == 1); // do n o t h i n g /* c r i t i c a l _ s e c t i o n _ 2 */

t u r n = 1;

/* r e m a i n d e r _ 2 */

} }

v o i d m a i n () {

t h r e a d _ t thread1 , t h r e a d 2 ;

p t h r e a d _ c r e a t e (& thread1 , NULL , P1 , N U L L );

p t h r e a d _ c r e a t e (& thread2 , NULL , P2 , N U L L );

p t h r e a d _ j o i n (& thread1 , N U L L );

p t h r e a d _ j o i n (& thread2 , N U L L );

}

(16)

Synchronization (Part 1)

16/55

First Attempt (contd.)

I

Satisfies mutual exclusion, no deadlock or lockout, but not loosely connected (think polar bears!)

I

Fairness: One process is forced to work at the pace of the other process.

This technique of passing control explicitly from one process to

another is known as coroutines.

(17)

Synchronization (Part 1)

17/55

The Igloo Metaphor (contd.)

(18)

Synchronization (Part 1)

18/55 int c1 = F A L S E ; /* s h a r e d v a r i a b l e c1 */

int c2 = F A L S E ; /* s h a r e d v a r i a b l e c2 */

v o i d P1 () { for ( ; ; ) {

w h i l e ( c2 ); // do n o t h i n g c1 = T R U E ;

/* c r i t i c a l _ s e c t i o n _ 1 */

c1 = F A L S E ; /* r e m a i n d e r _ 1 */

} }

v o i d P2 () { for ( ; ; ) {

w h i l e ( c1 ); // do n o t h i n g c2 = T R U E ;

/* c r i t i c a l _ s e c t i o n _ 2 */

c2 = F A L S E ; /* r e m a i n d e r _ 2 */

} }

v o i d m a i n () { /* s a m e as b e f o r e */}

(19)

Synchronization (Part 1)

19/55

Second Attempt (contd.)

I

Does not satisfy mutual exclusion.

I

Give an example interleaving that shows both processes in

the critical section.

(20)

Synchronization (Part 1)

20/55

Third Attempt

int c1 = F A L S E ; /* s h a r e d v a r i a b l e c1 */

int c2 = F A L S E ; /* s h a r e d v a r i a b l e c2 */

v o i d P1 () { for ( ; ; ) {

c1 = T R U E ;

w h i l e ( c2 ); // do n o t h i n g /* c r i t i c a l _ s e c t i o n _ 1 */

c1 = F A L S E ; /* r e m a i n d e r _ 1 */

} }

v o i d P2 () { for ( ; ; ) {

c2 = T R U E ;

w h i l e ( c1 ); // do n o t h i n g /* c r i t i c a l _ s e c t i o n _ 2 */

c2 = F A L S E ; /* r e m a i n d e r _ 2 */

} } v o i d m a i n () { /* s a m e as b e f o r e */}

(21)

Synchronization (Part 1)

21/55

Third Attempt (contd.)

I

This solution satisfies mutual exclusion but deadlocks.

I

However, it is still instructive to prove that the solution

satisfies mutual exclusion.

(22)

Synchronization (Part 1)

22/55

Fourth Attempt

int c1 = F A L S E ; /* s h a r e d v a r i a b l e c1 */

int c2 = F A L S E ; /* s h a r e d v a r i a b l e c2 */

v o i d P1 () { for ( ; ; ) {

c1 = T R U E ; w h i l e ( c2 ) {

c1 = F A L S E ; // do n o t h i n g for // a few m o m e n t s c1 = T R U E ; }

/* c r i t i c a l _ s e c t i o n _ 1 */

c1 = F A L S E ; /* r e m a i n d e r _ 1 */

} }

v o i d P2 () { for ( ; ; ) {

c2 = T R U E ; w h i l e ( c1 ) {

c2 = F A L S E ;

// do n o t h i n g for a few m o m e n t s c2 = T R U E ;

}

/* c r i t i c a l _ s e c t i o n _ 2 */

c2 = F A L S E ; /* r e m a i n d e r _ 2 */

} }

(23)

Synchronization (Part 1)

23/55

Fourth Attempt (contd.)

I

Does satisfy mutual exclusion.

I

Makes the processes more polite (or chivalrous). However, there can be such a thing as too much chivalry. This creates a potential lockout situation.

I

Come up with an example where the two processes lockout

due to too much chivalry!

(24)

Synchronization (Part 1)

24/55

The Igloo Metaphor (contd.)

(25)

Synchronization (Part 1)

25/55

Petersen’s Solution

int f l a g 1 = F A L S E ; /* s h a r e d v a r i a b l e f l a g 1 */

int f l a g 2 = F A L S E ; /* s h a r e d v a r i a b l e f l a g 2 */

int t u r n =1; /* s h a r e d v a r i a b l e t u r n */

v o i d P1 () { for ( ; ; ) {

f l a g 1 = T R U E ; t u r n = 2;

w h i l e ( f l a g 2 && ( t u r n == 2 ) ) ; // do n o t h i n g /* c r i t i c a l _ s e c t i o n _ 1 */

f l a g 1 = F A L S E ; /* r e m a i n d e r _ 1 */

} }

v o i d P2 () { for ( ; ; ) {

f l a g 2 = T R U E ; t u r n = 1;

w h i l e ( f l a g 1 && ( t u r n == 1 ) ) ; // do n o t h i n g /* c r i t i c a l _ s e c t i o n _ 2 */

f l a g 2 = F A L S E ; /* r e m a i n d e r _ 2 */

} }

v o i d m a i n () { /* s a m e as b e f o r e */}

(26)

Synchronization (Part 1)

26/55

Proof for Mutual Exclusion:

The following proof is symmetric and we show the arguments only for one case, i.e., for P1in its critical section. We have substituted flag 1 and flag 2 by an array flag [1..2] for notational convenience.

1. (When P1entered its critical section) then ((flag [2] = false) or (turn = 1)) This is due to the test in the while loop.

2. (When P1entered its critical section) then (flag [1] = true) This is true since the critical section is bracketed between assignments to flag [1].

3. ((turn = 1) and (flag [1] = true)) implies (P2cannot enter its critical section) This follows from the test in the while loop for P2.

4. (flag [2] = false) implies (P2is out of its critical section) flag [2] is set to false when P2leaves its critical section or in the initialization. Thus flag [2]

being false implies that P2is out of its critical section and is not intending to enter. If it intends to enter it will set flag [2] to true.

5. (When P1entered its critical section) then (P2is not in its critical section) Follows from (3) and (4).

6. (As long as P1is in its critical section) then (P2does not enter its critical section) This follows from (5). Since (5) refers to an arbitrary instant of time, then as long as its antecedent (P1in critical_section) remains true, so will its consequent (P2does not enter critical_section).

(27)

Synchronization (Part 1)

27/55

Proof for no deadlock

A deadlock can occur only if the processes are stuck in their while loops.

A process Pi is prevented from entering its critical section only if the condition flag [j] = true and turn = j where j is 1 if i is 2 and vice versa. If Pj has set flag [j] = true and is also executing in its while loop, then either turn = 1 or turn = 2, but cannot be both. Thus either P1 or P2will be able to enter its critical section and there is no deadlock.

(28)

Synchronization (Part 1)

28/55

Proof for no starvation

As noted in the previous proof, either P1or P2is able to enter the critical section if both attempt to enter at about the same time. To show that there is no starvation, we must show the following two things:

1. Once P1gets in to the critical section then it can’t prevent P2from getting its chance and vice versa.

Proof: Once P1exits its critical section, it will reset flag [1] = false allowing P2a chance to enter its critical section. If P1resets flag [1] = true in an attempt to quickly re-enter its critical section, it must also set turn = 2 (the politeness clause). Thus since P2does not change the value of the variable turn in the execution of the while statement, P2will enter its critical section after at most one entry by P1. The same argument applies if the role of P1and P2are interchanged.

2. If P1terminates in its remainder section (that is, out of its critical section) then that does not prevent P2from entering its critical section (and vice versa).

Proof: Follows from the fact that after leaving the critical section the process P1must set flag [1] = false allowing P2to enter its critical section.

Note that we assume that processes do not terminate during the critical section as well as during the pre-protocol and post-protocol where they are entering or leaving the critical section but they can die in the remainder section.

(29)

Synchronization (Part 1)

29/55

The Bakery Problem

u n s i g n e d int c h o o s i n g [ n ];

u n s i g n e d int n u m b e r [ n ];

// i n i t i a l v a l u e s :

// c h o o s i n g [ i ] = F A L S E ; 0 <= i <= n -1 // n u m b e r [ i ] = 0; 0 <= i <= n -1

v o i d p (int i ) {

for ( ; ; ) {

c h o o s i n g [ i ] = T R U E ;

n u m b e r [ i ] = MAX ( n u m b e r [0] , n u m b e r [1] , ... , n u m b e r [ n - 1 ] ) + 1 ; c h o o s i n g [ i ] = F A L S E ;

for ( j =0; j < n ; j ++) {

w h i l e ( c h o o s i n g [ j ]); // do n o t h i n g

// ( a , b ) < ( c , d ) if a < c or if a == c and b < d

w h i l e (( n u m b e r [ j ] != 0) && (( n u m b e r [ j ] , j ) < ( n u m b e r [ i ] , i ) ) ) ; }

/* c r i t i c a l s e c t i o n */

...

n u m b e r [ i ] = 0;

/* r e m a i n d e r */

} }

Does the above satisfy mutual exclusion? Does it prevent deadlock or lockout?

Can the numbers overflow? Check the examplecounting.c

(30)

Synchronization (Part 1)

30/55

Semaphores

A

semaphore s

is a non-negative integer variable. Once s has been given its initial value, the only permissible operations are:

P(s)

(or

wait(s)

or

down(s)). [if (s > 0) then s = s-1;

else {(wait until s > 0)}] If s > 0, it is tested and decremented as an atomic operation. However, if

s is zero, the process executing P can be

interrupted when it executes the wait command.

V(s)

(or

signal(s)

or

up(s)

or

post(s)). [s = s+1].

Increment s as an indivisible operation. The

effect is to signal some process that is blocked on

the semaphore.

(31)

Synchronization (Part 1)

31/55

Semaphores (contd.)

I

Semaphores can be

binary, that is, taking only values 0 or

1. A binary semaphores is often referred to as a

Mutex.

I

Or they can be

counting

or

general

semaphores, which can take on any value greater than or equal to zero.

I

If more than one process is blocked on a semaphore s, than an arbitrary one of these process is woken up by the V(s) operation.

I

P stands for proberen (to probe) and V stands for

verhogen (to increment) in Dutch. Semaphores were

introduced by E.W. Dijkstra.

The igloo metaphor: Now the igloo not only has a blackboard but also a deep-freezer.

(32)

Synchronization (Part 1)

32/55

A Train Semaphore

(33)

Synchronization (Part 1)

33/55

Critical Section Using a Semaphore

s e m a p h o r e m u t e x = 1; // m u s t be c r e a t e d and i n i t i a l i z e d in m a i n ()

p r o c e s s 0 () {

w h i l e ( T R U E ) {

< c o m p u t e section >

w a i t( m u t e x );

< c r i t i c a l section >

s i g n a l( m u t e x );

} }

p r o c e s s 1 () {

w h i l e ( T R U E ) {

< c o m p u t e section >

w a i t( m u t e x );

< c r i t i c a l section >

s i g n a l( m u t e x );

} }

(34)

Synchronization (Part 1)

34/55

Bank Account example using a semaphore

s e m a p h o r e m u t e x = 1; // m u s t be c r e a t e d and i n i t i a l i z e d in m a i n () p t h r e a d _ c r e a t e ( thread1 , 0);

p t h r e a d _ c r e a t e ( thread2 , 0);

...

/* t h r e a d 1 and t h r e a d 2 c a l l c r e d i t / d e b i t m u l t i p l e t i m e s */

...

c r e d i t () {

/* E n t e r c r i t i c a l s e c t i o n */

w a i t( m u t e x );

b a l a n c e = b a l a n c e + a m o u n t ; /* E x i t c r i t i c a l s e c t i o n */

s i g n a l( m u t e x );

}

d e b i t () {

/* E n t e r c r i t i c a l s e c t i o n */

w a i t( m u t e x );

b a l a n c e = b a l a n c e - a m o u n t ; /* E x i t c r i t i c a l s e c t i o n */

s i g n a l( m u t e x );

}

(35)

Synchronization (Part 1)

35/55

Interacting Parallel Processes

S h a r e d d o u b l e x , y ; // m u s t be c r e a t e d and s e t u p in m a i n ()

p r o c e s s A () {

w h i l e ( T R U E ) {

< c o m p u t e A1 >;

w r i t e ( x ); /* p r o d u c e x */

< c o m p u t e A2 >;

r e a d ( y ); /* c o n s u m e y */

} }

p r o c e s s B () {

w h i l e ( T R U E ) {

r e a d ( x ); /* c o n s u m e x */

< c o m p u t e B1 >;

w r i t e ( y ); /* p r o d u c e y */

< c o m p u t e B2 >;

} }

(36)

Synchronization (Part 1)

36/55

Synchronizing Processes

S h a r e d d o u b l e x , y ; // m u s t be c r e a t e d and s e t u p in m a i n () s e m a p h o r e s_x = 0 , s_y = 0;

p r o c e s s A () {

w h i l e ( T R U E ) {

< c o m p u t e A1 >;

w r i t e ( x ); /* p r o d u c e x */

s i g n a l( s_x ); /* s i g n a l B */

< c o m p u t e A2 >;

/* W a i t for s i g n a l f r o m B */

w a i t( s_y );

r e a d ( y ); /* c o n s u m e y */

} }

p r o c e s s B () {

w h i l e ( T R U E ) {

/* W a i t for s i g n a l f r o m A */

w a i t( s_x );

r e a d ( x ); /* c o n s u m e x */

< c o m p u t e B1 >;

w r i t e ( y ); /* p r o d u c e y */

s i g n a l( s_y ); /* s i g n a l A */

< c o m p u t e B2 >;

} }

(37)

Synchronization (Part 1)

37/55

Producers and Consumers

Consumer Consumer

Consumer Producer

Producer Producer Full Pool

Empty Pool

(38)

Synchronization (Part 1)

38/55

Producers and Consumers

p r o d u c e r () {

b u f _ t y p e * next , * h e r e ; w h i l e( T R U E ) {

p r o d u c e _ i t e m ( n e x t );

/* C l a i m an e m p t y b u f f e r */

w a i t( e m p t y );

w a i t( m u t e x );

h e r e = o b t a i n ( e m p t y );

s i g n a l( m u t e x );

c o p y _ b u f f e r ( next , h e r e );

w a i t( m u t e x );

r e l e a s e ( here , f u l l P o o l );

s i g n a l( m u t e x );

/* S i g n a l a f u l l b u f f e r */

s i g n a l( f u l l );

} }

s e m a p h o r e m u t e x = 1;

/* c o u n t i n g s e m a p h o r e s */

s e m a p h o r e f u l l = 0;

s e m a p h o r e e m p t y = N ; b u f _ t y p e b u f f e r [ N ];

p t h r e a d _ c r e a t e ( p r o d u c e r , 0);

p t h r e a d _ c r e a t e ( c o n s u m e r , 0);

c o n s u m e r () {

b u f _ t y p e * next , * h e r e ; w h i l e( T R U E ) {

/* C l a i m f u l l b u f f e r */

w a i t( f u l l );

/* M a n i p u l a t e the p o o l */

w a i t( m u t e x );

h e r e = o b t a i n ( f u l l );

s i g n a l( m u t e x );

c o p y _ b u f f e r ( here , n e x t );

/* M a n i p u l a t e the p o o l */

w a i t( m u t e x );

r e l e a s e ( here , e m p t y P o o l );

s i g n a l( m u t e x );

/* S i g n a l an e m p t y b u f f e r */

s i g n a l( e m p t y );

c o n s u m e _ i t e m ( n e x t );

} }

(39)

Synchronization (Part 1)

39/55

More on Producers and Consumers

I

What happens if we interchange the wait(full) and wait(mutex) operations? (in the consumer)

I

What happens if we interchange the signal(full) and signal(mutex) operations? (in the consumer)

I How to improve the performance while retaining correctness?

I Separate semaphores for full/empty pools?

I Multiple queues?

I For multiple queues, should we let producers and

consumers access a queue at random or should there be a systematic pattern of access?

(40)

Synchronization (Part 1)

40/55

Synchronization in POSIX Threads (PThreads)

Mutexesare simple lock primitives that can be used to control access to a shared resource.

# include< p t h r e a d . h >

p t h r e a d _ m u t e x _ t < v a r i a b l e >;

p t h r e a d _ m u t e x _ i n i t (p t h r e a d _ m u t e x _ t * , p t h r e a d _ m u t e x a t t r _ t *) p t h r e a d _ m u t e x _ l o c k (p t h r e a d _ m u t e x _ t *)

p t h r e a d _ m u t e x _ t r y l o c k (p t h r e a d _ m u t e x _ t *) p t h r e a d _ m u t e x _ u n l o c k (p t h r e a d _ m u t e x _ t *) p t h r e a d _ m u t e x _ d e s t r o y (p t h r e a d _ m u t e x _ t *)

semaphoresin POSIX threads support the following operations.

# include< p t h r e a d . h >

# i n c l u d e <s e m a p h o r e. h >

s e m _ t < v a r i a b l e >;

int s e m _ i n i t (s e m _ t * sem , int pshared , u n s i g n e d int v a l u e );

int s e m _ w a i t (s e m _ t * sem );

int s e m _ t r y w a i t (s e m _ t * sem );

int s e m _ p o s t (s e m _ t * sem );

int s e m _ g e t v a l u e (s e m _ t * sem , int * s v a l );

int s e m _ d e s t r o y (s e m _ t * sem );

(41)

Synchronization (Part 1)

41/55

PThreads Synchronization

I Mutex

- A construct used to protect access to a shared bit of memory.

I

Think of a lock that only has one key. If you want to open the lock you must get the key. If you don’t have the key you must wait until it becomes available.

I

A

Mutex, short for Mutual exclusion object, is an object

that allows multiple program threads to share the same

resource, such as a data structure or file access, but not

simultaneously. Each thread locks the mutex to gain

access to the shared resource and then unlocks when it is

done. We can use mutexes to prevent race conditions.

(42)

Synchronization (Part 1)

42/55

Mutual Exclusion Using Locks

p t h r e a d _ m u t e x _ t m u t e x ; v o i d P1 () {

for ( ; ; ) {

p t h r e a d _ m u t e x _ l o c k ( & m u t e x );

/* c r i t i c a l _ s e c t i o n _ 1 */

p t h r e a d _ m u t e x _ u n l o c k ( & m u t e x );

/* r e m a i n d e r _ 1 */

} }

v o i d P2 () { for ( ; ; ) {

p t h r e a d _ m u t e x _ l o c k ( & m u t e x );

/* c r i t i c a l _ s e c t i o n _ 2 */

p t h r e a d _ m u t e x _ u n l o c k ( & m u t e x );

/* r e m a i n d e r _ 2 */

} }

v o i d m a i n () {

t h r e a d _ t thread1 , t h r e a d 2 ; p t h r e a d _ m u t e x _ i n i t (& mutex , N U L L );

p t h r e a d _ c r e a t e ( thread1 , NULL , P1 , N U L L );

p t h r e a d _ c r e a t e ( thread2 , NULL , P2 , N U L L );

p a u s e (); // let the t h r e a d s p l a y f o r e v e r }

(43)

Synchronization (Part 1)

43/55

Semaphores in Pthreads

#include <semaphore.h>

int sem_init(sem_t *sem, int pshared, unsigned int value);Initializes the semaphore object pointed to by sem. The count associated with the semaphore is set initially to value. The flag pshared should be set to zero.

Non-zero value allows semaphores to be shared across processes.

int sem_wait(sem_t *sem);Suspends the calling thread until the semaphore pointed to by sem has non-zero count. It then atomically decreases the semaphore count.

int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);

int sem_trywait(sem_t *sem);A non-blocking variant of sem_wait

int sem_post(sem_t *sem);Atomically increases the count of the semaphore pointed to by sem. This function never blocks and can safely be used in asynchronous signal handlers.

int sem_getvalue(sem_t *sem, int *sval);

int sem_destroy(sem_t *sem);

(44)

Synchronization (Part 1)

44/55

PThread Synchronization Examples

I

See the example

safe-bank-balance.c

for a solution to the

race condition

using a

Mutex

lock.

I

Sychronized hello world:

threads-hello-synchronized.c

I

File copy using two threads (reader and writer):

threads-sem-cp.c

I

File copy using double buffering:

threads-dbl-buf.c

(45)

Synchronization (Part 1)

45/55

In-class Exercise (1)

Dining Philosophers? Dining Semaphores? We have 5 philosophers that sit around a table. There are 5 bowls of rather entangled spaghetti that they can eat if they get hungry. There are five forks on the table as well. However, each philosopher needs two forks to eat the tangled spaghetti. No two philosophers can grab the same fork at the same time.

We want the philosophers to be able to eat amicably. Consider the following solution to this problem.

/* dining_philosophers */

sem_t fork[5]; // array of binary semaphores sem_t table; // general semaphore

void philosopher(void *arg) {

i = *(int *) arg;

for (;;) { think();

sem_wait(&table);

sem_wait(&fork[i]);

sem_wait(&fork[(i+1) % 5];

eat();

sem_post(&fork[i]);

sem_post(&fork[(i+1) % 5];

sem_post(&table);

} }

(46)

Synchronization (Part 1)

46/55

In-class Exercise (2)

. . . int main() {

int i;

for (i = 0; i< 5; i++) {

sem_init(&fork[i], 0, 1); //initialize to 1 }

sem_init(&table, 0, 4); //initialize to 4 for (i = 0; i< 5; i++) {

pthread_create(&tid[i], NULL, philosopher, (void *)&i);

}

for (i = 0; i< 5; i++) { pthread_join(tid[i], NULL);

} exit(0);

}

I Argue why it is not possible for more than one philosopher to grab the same fork?

I Can the philosophers ever deadlock. Explain.

I Can a philosopher starve?

I What may happen if we initialize the table semaphore to 5 (instead of 4)?

(47)

Synchronization (Part 1)

47/55

Other Useful Thread Functions

I pthread_yield()Informs the scheduler that the thread is willing to yield its quantum, requires no arguments.

I pthread_t me = pthread_self()Allows a pthread to obtain its own identifier

I pthread_detach(thread)Informs the library that the threads exit status will not be needed by subsequent pthread_join calls resulting in better threads performance.

I Barriers(Not available in Mac OS X) p t h r e a d _ b a r r i e r _ t b a r r i e r ;

p t h r e a d _ b a r r i e r _ i n i t (& barrier , NULL , c o u n t );

r e s u l t = p t h r e a d _ b a r r i e r _ w a i t (& b a r r i e r );

/* One t h r e a d g e t s P T H R E A D _ B A R R I E R _ S E R I A L _ T H R E A D b a c k w h i l e o t h e r s get a z e r o */

p t h r e a d _ b a r r i e r _ d e s t r o y (& b a r r i e r );

See the examplethreads-barrier.c.

(48)

Synchronization (Part 1)

48/55

Further Information on POSIX Threads

I

Where can I find out more about Threads? On Linux, try

man -k pthread

to see the man pages for Pthreads (pthreads) package.

I

Check out the following books:

I Lewis and Berg: Multithreaded Programming with Pthreads (Prentice Hall)

(49)

Synchronization (Part 1)

49/55

Synchronization in MS Windows API

MS Windows API supports

Mutex

and

semaphore

objects.

I

The methods for Mutexes include

CreateMutex(..), WaitForSingleObject(...)

to wait for it and

ReleaseMutex(...)

to release the Mutex.

I

The methods for semaphores include

CreateSemaphore(..),

WaitForSingleObject(...)

to wait for it and

ReleaseSemaphore(...)

to release the semaphore.

I

A

WaitForMultipleObjects(..)

call is also provided.

(50)

Synchronization (Part 1)

50/55

Threads in MS Windows API

Get detailed information from http://msdn.microsoft.com/library/.

H A N D L E W I N A P I C r e a t e T h r e a d (

L P S E C U R I T Y _ A T T R I B U T E S l p T h r e a d A t t r i b u t e s , S I Z E _ T d w S t a c k S i z e ,

L P T H R E A D _ S T A R T _ R O U T I N E l p S t a r t A d d r e s s , L P V O I D l p P a r a m e t e r ,

D W O R D d w C r e a t i o n F l a g s , L P D W O R D l p T h r e a d I d );

D W O R D W I N A P I T h r e a d P r o c ( L P V O I D l p P a r a m e t e r );

(51)

Synchronization (Part 1)

51/55

Semaphores and Mutexes in MS Windows API

H A N D L E W I N A P I C r e a t e S e m a p h o r e (

L P S E C U R I T Y _ A T T R I B U T E S l p S e m a p h o r e A t t r i b u t e s , L O N G l I n i t i a l C o u n t ,

L O N G l M a x i m u m C o u n t , L P C T S T R l p N a m e );

B O O L W I N A P I R e l e a s e S e m a p h o r e ( H A N D L E h S e m a p h o r e ,

L O N G l R e l e a s e C o u n t , L P L O N G l p P r e v i o u s C o u n t );

H A N D L E W I N A P I C r e a t e M u t e x (

L P S E C U R I T Y _ A T T R I B U T E S l p M u t e x A t t r i b u t e s , B O O L b I n i t i a l O w n e r ,

L P C T S T R l p N a m e );

B O O L W I N A P I R e l e a s e M u t e x (H A N D L E h M u t e x );

(52)

Synchronization (Part 1)

52/55

Wait calls in MS Windows API

D W O R D W I N A P I W a i t F o r S i n g l e O b j e c t ( H A N D L E hHandle ,

D W O R D d w M i l l i s e c o n d s );

D W O R D W I N A P I W a i t F o r M u l t i p l e O b j e c t s ( D W O R D nCount ,

c o n s t H A N D L E* l p H a n d l e s , B O O L b W a i t A l l ,

D W O R D d w M i l l i s e c o n d s );

(53)

Synchronization (Part 1)

53/55

Critical Section call in MS Windows API

C R I T I C A L _ S E C T I O N cs ;

I n i t i a l i z e C r i t i c a l S e c t i o n (& cs );

E n t e r C r i t i c a l S e c t i o n (& cs );

L e a v e C r i t i c a l S e c t i o n (& cs );

(54)

Synchronization (Part 1)

54/55

Multithreaded Example in MS Windows API

I

Code Example:

thread-sem-cp.c

(55)

Synchronization (Part 1)

55/55

Synchronization in Java

I

Java has the

synchronized

keyword for guaranteeing mutually exclusive access to a method or a block of code.

Only one thread can be active among all synchronized methods and synchronized blocks of code in a class.

I

Java provides a mutex/lock implementation via the class

ReentrantLock

in the

java.util.concurrent.lock

package.

I

Java provides sempahore implementation via the class

Semaphore

in the

java.util.concurrent

package.

I

Java synchronization will be covered in the next chapter as

it is based on the concept of a Monitor, which is covered

in the next chapter.

References

Related documents

Key words: Ahtna Athabascans, Community Subsistence Harvest, subsistence hunting, GMU 13 moose, Alaska Board o f Game, Copper River Basin, natural resource management,

‘I thought “here goes” and we’ll just leave it at that … I should have, but I thought they might make you go onto another thing that costs more.’ This borrower said that

All stationary perfect equilibria of the intertemporal game approach (as slight stochastic perturbations as in Nash (1953) tend to zero) the same division of surplus as the static

Based on quality management principles Customer focused Leadership Involvement of people Process Approach System Approach Continual Improvement. Factual Approach to Decision

I further understand that La Trobe University, as an education provider, is required to provide information about my enrolment and my contact details in Australia to the Department

Ten years into the reign of Thorin the First, son of Thráin the Old, the King resolved to remove the royal house of Durin’s folk from Erebor to abide in the Grey Mountains.. At the

Step 1: Draw the configuration diagram.. • Problem 11: For the mechanism shown in figure link 2 rotates at constant angular velocity of 1 rad/sec construct the velocity polygon

According to the new regulations the water supplier is required to submit an Emergency Response and Contingency Plan (ERCP). An ERCP is a written document that spells out a