programming with threads topics threads shared variables the need for synchronization synchronizing...

44
Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races and deadlocks threads1.ppt CS 105 “Tour of the Black Holes of Computing!”

Upload: paxton-storm

Post on 16-Dec-2015

234 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

Programming with Threads

Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races and deadlocks

threads1.ppt

CS 105“Tour of the Black Holes of Computing!”

Page 2: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 2 – CS 105

Traditional View of a Process

Process = process context + code, data, and stack

shared libraries

run-time heap

0

read/write data

Program context: Data registers Condition codes Stack pointer (SP) Program counter (PC)Kernel context: VM structures Descriptor table brk pointer

Code, data, and stack

read-only code/data

stackSP

PC

brk

Process context

Page 3: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 3 – CS 105

Alternate View of a Process

Process = thread + code, data, and kernel context

shared libraries

run-time heap

0

read/write dataThread context: Data registers Condition codes Stack pointer (SP) Program counter (PC)

Code and Data

read-only code/data

stackSP

PC

brk

Thread (main thread)

Kernel context: VM structures Descriptor table brk pointer

Page 4: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 4 – CS 105

A Process With Multiple ThreadsMultiple threads can be associated with a process

Each thread has its own logical control flow (sequence of PC values)

Each thread shares the same code, data, and kernel context Each thread has its own thread id (TID)

shared libraries

run-time heap

0

read/write dataThread 1 context: Data registers Condition codes SP1 PC1

Shared code and data

read-only code/data

stack 1

Thread 1 (main thread)

Kernel context: VM structures Descriptor table brk pointer

Thread 2 context: Data registers Condition codes SP2 PC2

stack 2

Thread 2 (peer thread)

Page 5: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 5 – CS 105

Logical View of Threads

Threads associated with a process form a pool of peers Unlike processes, which form a tree hierarchy

P0

P1

sh sh sh

foo

bar

T1

Process hierarchyThreads associated with process foo

T2T4

T5 T3

shared code, dataand kernel context

Page 6: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 6 – CS 105

Concurrent Thread Execution

Two threads run concurrently (are concurrent) if their logical flows overlap in time

Otherwise, they are sequential (just like processes)

Examples: Concurrent: A & B, A&C Sequential: B & C

Time

Thread A Thread B Thread C

Page 7: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 7 – CS 105

Threads vs. Processes

How threads and processes are similar Each has its own logical control flow Each can run concurrently Each is context switched

How threads and processes are different Threads share code and data, processes (typically) do not Threads are somewhat less expensive than processes

Process control (creating and reaping) is twice as expensive as thread control

Linux/Pentium III numbers:

» ~20K cycles to create and reap a process

» ~10K cycles to create and reap a thread

Page 8: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 8 – CS 105

Posix Threads (Pthreads) InterfacePthreads: Standard interface for ~60 functions that

manipulate threads from C programs Creating and reaping threads

pthread_create, pthread_join Determining your thread ID

pthread_self Terminating threads

pthread_cancel, pthread_exitexit [terminates all threads] , return [terminates current

thread]

Synchronizing access to shared variablespthread_mutex_init, pthread_mutex_[un]lockpthread_cond_init, pthread_cond_[timed]wait

Page 9: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 9 – CS 105

The Pthreads "hello, world" Program

/* * hello.c - Pthreads "hello, world" program */#include "csapp.h"

void *howdy(void *vargp);

int main() { pthread_t tid;

Pthread_create(&tid, NULL, howdy, NULL); Pthread_join(tid, NULL); exit(0);}

/* thread routine */void *howdy(void *vargp) { printf("Hello, world!\n"); return NULL;}

Thread attributes (usually NULL)

Thread arguments(void *p)

return value(void **p)

Page 10: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 10 – CS 105

Execution of Threaded “hello, world”

main thread

peer thread

return NULL;main thread waits for peer thread to terminate

exit() terminates

main thread and any peer threads

call Pthread_create()

call Pthread_join()

Pthread_join() returns

printf()

(peer threadterminates)

Pthread_create() returns

Page 11: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 11 – CS 105

Pros and Consof Thread-Based Designs

+ Easy to share data structures between threads E.g., logging information, file cache

+ Threads are more efficient than processes

– Unintentional sharing can introduce subtle and hard-to-reproduce errors! Ease of data sharing is greatest strength of threads Also greatest weakness!

Page 12: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 12 – CS 105

Shared Variables in Threaded C ProgramsQuestion: Which variables in a threaded C program are

shared variables? Answer not as simple as “global variables are shared” and

“stack variables are private”

Requires answers to the following questions: What is the memory model for threads? How are variables mapped to memory instances? How many threads reference each of these instances?

Page 13: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 13 – CS 105

Threads Memory ModelConceptual model:

Each thread runs in the context of a process Each thread has its own separate thread context

Thread ID, stack, stack pointer, program counter, condition codes, and general purpose registers

All threads share remaining process context Code, data, heap, and shared library segments of process virtual

address space Open files and installed handlers

Operationally, this model is not strictly enforced: Register values are truly separate and protected But any thread can read and write the stack of any other thread

Mismatch between conceptual and operational model is a source of confusion and errors

Page 14: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 14 – CS 105

Example of Threads Accessing Another Thread’s Stack

char **ptr; /* global */

int main(){ int i; pthread_t tid; char *msgs[N] = { "Hello from foo", "Hello from bar" }; ptr = msgs; for (i = 0; i < 2; i++) Pthread_create(&tid, NULL, thread, (void *)i); Pthread_exit(NULL);}

/* thread routine */void *thread(void *vargp){ int myid = (int)vargp; static int svar = 0; printf("[%d]: %s (svar=%d)\n", myid, ptr[myid], ++svar);}

Peer threads access main thread’s stackindirectly through global ptr variable

Page 15: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 15 – CS 105

Mapping Vars to Mem. Instances

char **ptr; /* global */

int main(){ int i; pthread_t tid; char *msgs[N] = { "Hello from foo", "Hello from bar" }; ptr = msgs; for (i = 0; i < 2; i++) Pthread_create(&tid, NULL, thread, (void *)i); Pthread_exit(NULL);}

/* thread routine */void *thread(void *vargp){ int myid = (int)vargp; static int svar = 0; printf("[%d]: %s (svar=%d)\n", myid, ptr[myid], ++svar);}

Global var: 1 instance (ptr [data])

Local static var: 1 instance (svar [data])

Local automatic vars: 1 instance (i.m, msgs.m )

Local automatic var: 2 instances ( myid.p0[peer thread 0’s stack], myid.p1[peer thread 1’s stack])

Page 16: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 16 – CS 105

Shared Variable Analysis

Which variables are shared?

Variable Referenced by Referenced by Referenced byinstance main thread? peer thread 0? peer thread 1?

ptr yes yes yessvar no yes yesi.m yes no nomsgs.m yes yes yesmyid.p0 no yes nomyid.p1 no no yes

Answer: A variable x is shared iff multiple threads reference at least one instance of x. Thus: ptr, svar, and msgs are shared. i and myid are NOT shared.

Page 17: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 17 – CS 105

badcnt.c: An Improperly Synchronized Threaded Programunsigned int cnt = 0; /* shared */

int main() { pthread_t tid1, tid2; Pthread_create(&tid1, NULL, count, NULL); Pthread_create(&tid2, NULL, count, NULL);

Pthread_join(tid1, NULL); Pthread_join(tid2, NULL);

if (cnt != (unsigned)NITERS*2) printf("BOOM! cnt=%d\n", cnt); else printf("OK cnt=%d\n", cnt);}

/* thread routine */void *count(void *arg) { int i; for (i=0; i<NITERS; i++) cnt++; return NULL;}

linux> ./badcntBOOM! cnt=198841183

linux> ./badcntBOOM! cnt=198261801

linux> ./badcntBOOM! cnt=198269672

cnt should be200,000,000.

What went wrong?!

Page 18: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 18 – CS 105

Assembly Code for Counter Loop

.L9:movl -4(%ebp),%eaxcmpl $99999999,%eaxjle .L12jmp .L10

.L12:movl cnt,%eax # Loadleal 1(%eax),%edx # Updatemovl %edx,cnt # Store

.L11:movl -4(%ebp),%eaxleal 1(%eax),%edxmovl %edx,-4(%ebp)jmp .L9

.L10:

Corresponding asm codefor (i=0; i<NITERS; i++) cnt++;

C code for counter loop

Head (Hi)

Tail (Ti)

Load cnt (Li)Update cnt (Ui)

Store cnt (Si)

Page 19: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 19 – CS 105

Concurrent ExecutionKey idea: In general, any sequentially consistent

interleaving is possible, but some are incorrect! Ii denotes that thread i executes instruction I %eaxi is the contents of %eax in thread i’s context

H1

L1

U1

S1

H2

L2

U2

S2

T2

T1

1111222221

-011-----1

0001111222

i (thread) instri cnt%eax1

OK

-----1222-

%eax2

Page 20: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 20 – CS 105

What Is“Sequential Consistency?”Two (or more) parallel executions are sequentially

consistent iff instructions of each thread (or process) are executed in sequential order No restrictions on how threads relate to each other Each thread runs at arbitrary speed Any interleaving is legitimate

Any (or all) instructions of B can run between any two instructions of A

Page 21: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 21 – CS 105

Concurrent Execution (cont)

Incorrect ordering: two threads increment the counter, but the result is 1 instead of 2

H1

L1

U1

H2

L2

S1

T1

U2

S2

T2

1112211222

-01--11---

0000011111

i (thread) instri cnt%eax1

----0--111

%eax2

Oops!

Page 22: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 22 – CS 105

Concurrent Execution (cont)

How about this ordering?

H1

L1

H2

L2

U2

S2

U1

S1

T1

T2

1122221112

i (thread) instri cnt%eax1 %eax2

We can clarify our understanding of concurrentexecution with the help of the progress graph

Page 23: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 23 – CS 105

Progress GraphsA progress graph depictsthe discrete execution state space of concurrent threads.

Each axis corresponds tothe sequential order ofinstructions in a thread.

Each point corresponds toa possible execution state(Inst1, Inst2).

E.g., (L1, S2) denotes statewhere thread 1 hascompleted L1 and thread2 has completed S2.

H1 L1 U1 S1 T1

H2

L2

U2

S2

T2

Thread 1

Thread 2

(L1, S2)

Page 24: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 24 – CS 105

Trajectories in Progress Graphs

A trajectory is a sequence of legal state transitions that describes one possible concurrent execution ofthe threads.

Example:

H1, L1, U1, H2, L2, S1, T1, U2, S2, T2

H1 L1 U1 S1 T1

H2

L2

U2

S2

T2

Thread 1

Thread 2

Page 25: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 25 – CS 105

Critical Sections and Unsafe Regions

L, U, and S form a critical section withrespect to the sharedvariable cnt.

Instructions in criticalsections (wrt to someshared variable) should not be interleaved.

Sets of states where suchinterleaving occursform unsafe regions.

H1 L1 U1 S1 T1

H2

L2

U2

S2

T2

Thread 1

Thread 2

Unsafe region

critical section wrt cnt

critical section wrt cnt

Page 26: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 26 – CS 105

Safe and Unsafe Trajectories

Def: A trajectory is safe iff it doesn’t enter any part of an unsafe region.

Claim: A trajectory is correct (wrt cnt) iff it issafe.

H1 L1 U1 S1 T1

H2

L2

U2

S2

T2

Thread 1

Thread 2

Unsafe region Unsafetrajectory

Safe trajectory

critical section wrt cnt

critical section wrt cnt

Page 27: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 27 – CS 105

Semaphores

Question: How can we guarantee a safe trajectory? Synchronize threads so they never enter unsafe state

Classic solution: Dijkstra's P and V operations on semaphores Semaphore: non-negative integer synchronization variable

P(s): while(1){[ if (s>0) {s--; break}] wait_a_while()}» Dutch for “test” ("Proberen“)

V(s): [ s++; ]» Dutch for “increment” ("Verhogen")

OS guarantees that operations between brackets [ ] are executed indivisibly

Only one P or V operation at a time can modify sWhen while loop in process X terminates, only that process has

decremented s

Semaphore invariant: (s >= 0)

Page 28: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 28 – CS 105

Safe Sharing with Semaphores

Here is how we would use P and V operations to synchronize the threads that update cnt

/* Semaphore s is initially 1 */

/* Thread routine */void *count(void *arg){ int i;

for (i=0; i<NITERS; i++) { P(s); cnt++; V(s); } return NULL;}

Page 29: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 29 – CS 105

Safe Sharing With Semaphores

Provide mutually exclusive access to shared variable by surrounding critical section with P and V operations on semaphores (initially set to 1).

Semaphore invariant creates forbidden regionthat encloses unsafe region and is never touched by any trajectory.

H1 P(s) V(s) T1

Thread 1

Thread 2

L1 U1 S1

H2

P(s)

V(s)

T2

L2

U2

S2

Unsafe region

Forbidden region

1 1 0 0 0 0 1 1

1 1 0 0 0 0 1 1

0 0 -1 -1 -1 -1 0 0

0 0-1 -1 -1 -1

0 0

0 0-1 -1 -1 -1

0 0

0 0

-1 -1 -1 -1

0 0

1 1 0 0 0 0 1 1

1 1 0 0 0 0 1 1

Initiallys = 1

Page 30: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 30 – CS 105

POSIX Semaphores

/* Initialize semaphore sem to value *//* pshared=0 if thread, pshared=1 if process */void Sem_init(sem_t *sem, int pshared, unsigned int value) { if (sem_init(sem, pshared, value) == -1) unix_error("Sem_init");}

/* P operation on semaphore sem */void P(sem_t *sem) { if (sem_wait(sem) == -1) unix_error("P");}

/* V operation on semaphore sem */void V(sem_t *sem) { if (sem_post(sem) == -1) unix_error("V");}

Page 31: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 31 – CS 105

Sharing With POSIX Semaphores/* goodcnt.c - properly sync’dcounter program */#include "csapp.h"#define NITERS 10000000

unsigned int cnt; /* counter */sem_t sem; /* semaphore */

int main() { pthread_t tid1, tid2;

Sem_init(&sem, 0, 1); /* sem=1 */

/* create 2 threads and wait */ ...

if (cnt != (unsigned)NITERS*2) printf("BOOM! cnt=%d\n", cnt); else printf("OK cnt=%d\n", cnt); exit(0);}

/* thread routine */void *count(void *arg){ int i;

for (i=0; i<NITERS; i++) { P(&sem); cnt++; V(&sem); } return NULL;}

Page 32: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 32 – CS 105

Signaling With Semaphores

Common synchronization pattern: Producer waits for slot, inserts item in buffer, and “signals” consumer Consumer waits for item, removes it from buffer, and “signals”

producer “Signals” in this context has nothing to do with Unix signals

Examples Multimedia processing:

Producer creates MPEG video frames, consumer renders the frames

Event-driven graphical user interfaces Producer detects mouse clicks, mouse movements, and keystrokes and

inserts corresponding events in buffer Consumer retrieves events from buffer and paints display

producerthread

sharedbuffer

consumerthread

Page 33: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 33 – CS 105

Producer-Consumer on a Buffer That Holds One Item

/* buf1.c - producer-consumeron 1-element buffer */#include “csapp.h”

#define NITERS 5

void *producer(void *arg);void *consumer(void *arg);

struct { int buf; /* shared var */ sem_t full; /* sems */ sem_t empty;} shared;

int main() { pthread_t tid_producer; pthread_t tid_consumer;

/* initialize the semaphores */ Sem_init(&shared.empty, 0, 1); Sem_init(&shared.full, 0, 0);

/* create threads and wait */ Pthread_create(&tid_producer, NULL, producer, NULL); Pthread_create(&tid_consumer, NULL, consumer, NULL); Pthread_join(tid_producer, NULL); Pthread_join(tid_consumer, NULL); exit(0);}

Page 34: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 34 – CS 105

Producer-Consumer (cont)

/* producer thread */void *producer(void *arg) { int i, item;

for (i=0; i<NITERS; i++) { /* produce item */ item = i; printf("produced %d\n", item);

/* write item to buf */ P(&shared.empty); shared.buf = item; V(&shared.full); } return NULL;}

/* consumer thread */void *consumer(void *arg) { int i, item;

for (i=0; i<NITERS; i++) { /* read item from buf */ P(&shared.full); item = shared.buf; V(&shared.empty);

/* consume item */ printf("consumed %d\n", item); } return NULL;}

Initially: empty = 1, full = 0.

Page 35: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 35 – CS 105

Thread Safety

Functions called from a thread must be thread-safe

We identify four (non-disjoint) classes of thread-unsafe functions: Class 1: Failing to protect shared variables Class 2: Relying on persistent state across invocations Class 3: Returning pointer to static variable Class 4: Calling thread-unsafe functions

Page 36: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 36 – CS 105

Thread-Unsafe Functions

Class 1: Failing to protect shared variables Fix: Use P and V semaphore operations Issue: Synchronization operations will slow down code Example: goodcnt.c

Page 37: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 37 – CS 105

Thread-Unsafe Functions (cont)Class 2: Relying on persistent state across multiple

function invocations Random number generator relies on static state Fix: Rewrite function so that caller passes in all necessary

state

/* rand - return pseudo-random integer on 0..32767 */ int rand(void) { static unsigned int next = 1; next = next*1103515245 + 12345; return (unsigned int)(next/65536) % 32768; } /* srand - set seed for rand() */ void srand(unsigned int seed) { next = seed; }

Page 38: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 38 – CS 105

Thread-Unsafe Functions (cont)Class 3: Returning pointer

to static variable

Fixes: 1. Rewrite code so caller

passes pointer to struct» Issue: Requires

changes in caller and callee

2. Lock-and-copy» Issue: Requires only

simple changes in caller (and none in callee)

» However, caller must free memory

hostp = Malloc(...));gethostbyname_r(name, hostp);

struct hostent *gethostbyname(char* name){ static struct hostent h; <contact DNS and fill in h> return &h;}

struct hostent *gethostbyname_ts(char *p) { struct hostent *q = Malloc(...); P(&mutex); /* lock */ p = gethostbyname(name); *q = *p; /* copy */ V(&mutex); return q;}

Page 39: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 39 – CS 105

Thread-Unsafe Functions

Class 4: Calling thread-unsafe functions Calling one thread-unsafe function makes an entire function

thread-unsafe

Fix: Modify the function so it calls only thread-safe functions

Page 40: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 40 – CS 105

Reentrant FunctionsA function is reentrant iff it accesses NO shared variables when called from multiple threads

Reentrant functions are a proper subset of the set of thread-safe functions

NOTE: The fixes to Class 2 and 3 thread-unsafe functions require modifying the function to make it reentrant (only first fix for Class 3 is reentrant)

Reentrantfunctions

All functions

Thread-unsafefunctions

Thread-safefunctions

Page 41: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 41 – CS 105

Thread-Safe Library Functions

Most functions in the Standard C Library (at the back of your K&R text) are thread-safe Examples: malloc, free, printf, scanf

All Unix system calls are thread-safe

Library calls that aren’t thread-safe:

Thread-unsafe function Class Reentrant versionasctime 3 asctime_rctime 3 ctime_rgethostbyaddr 3 gethostbyaddr_rgethostbyname 3 gethostbyname_rinet_ntoa 3 (none)localtime 3 localtime_rrand 2 rand_r

Page 42: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 42 – CS 105

Races

Race happens when program correctness depends on one thread reaching point x before another thread reaches point y

/* a threaded program with a race */int main() { pthread_t tid[N]; int i; for (i = 0; i < N; i++) Pthread_create(&tid[i], NULL, thread, &i); for (i = 0; i < N; i++) Pthread_join(tid[i], NULL); exit(0);}

/* thread routine */void *thread(void *vargp) { int myid = *((int *)vargp); printf("Hello from thread %d\n", myid); return NULL;}

Page 43: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 43 – CS 105

deadlockregion

Deadlock

P(s) V(s)

V(t)

Thread 1

Thread 2

Initially, s=t=1

P(t)

P(t) V(t)

forbiddenregion for s

forbiddenregion for t

P(s)

V(s) deadlockstate

Locking introducespotential for deadlock: waiting for a condition that will never be true.

Any trajectory that entersdeadlock region willeventually reachdeadlock state, waiting for either s or t to become nonzero.

Other trajectories luck out and skirt deadlock region.

Unfortunate fact: deadlock is often non-deterministic.

Page 44: Programming with Threads Topics Threads Shared variables The need for synchronization Synchronizing with semaphores Thread safety and reentrancy Races

– 44 – CS 105

Threads Summary

Threads provide another mechanism for writing concurrent programs

Threads are growing in popularity Somewhat cheaper than processes Easy to share data between threads

However, the ease of sharing has a cost: Easy to introduce subtle synchronization errors Tread carefully with threads!

For more info: D. Butenhof, “Programming with Posix Threads”, Addison-

Wesley, 1997