Shared Variable Analysis in Multi-threaded Programs: Critical Sections and Synchronization, Slides of Advanced Operating Systems

Shared variables in threaded c programs, focusing on critical sections and synchronization. It covers the memory model for threads, variable mapping to memory instances, and the importance of controlling cooperation between threads using synchronization. The document also includes examples of threads accessing each other's stacks and the impact of incorrect ordering on concurrent execution.

Typology: Slides

2011/2012

Uploaded on 08/06/2012

dharmesh
dharmesh 🇮🇳

4.1

(9)

87 documents

1 / 29

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
Lecture No. 9
docsity.com
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13
pf14
pf15
pf16
pf17
pf18
pf19
pf1a
pf1b
pf1c
pf1d

Partial preview of the text

Download Shared Variable Analysis in Multi-threaded Programs: Critical Sections and Synchronization and more Slides Advanced Operating Systems in PDF only on Docsity!

  • Lecture No.

Overview of today’s lecture

 Shared variable analysis in multi-threaded

programs

 Concurrency and synchronization

 Critical sections

 Solutions to the critical section problem

 Concurrency examples

 Re-cap of lecture

Threads Memory Model

 Conceptual 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 the remaining process context.

 Code, data, heap, and shared library segments of the process virtual address space.

 Open files and installed handlers

 Operationally, this model is not strictly enforced:

 While register values are truly separate and protected....

 Any thread can read and write the stack of any other thread.

 Mismatch between the conceptual and operation model is a source of
confusion and errors.

What resources are shared?

 Local variables are not shared

 refer to data on the stack, each thread has its own stack  never pass/share/store a pointer to a local variable on another thread’s stack!

 Global variables are shared

 stored in the static data segment, accessible by any thread

 Dynamic objects are shared

 stored in the heap, shared if you can name it

 in C, can conjure up the pointer  e.g., void *x = (void *) 0xDEADBEEF

 in Java, strong typing prevents this

 must pass references explicitly

 For correctness, we have to control this cooperation

 must assume threads interleave executions arbitrarily and at different rates  scheduling is not under application writers’ control

 We control cooperation using synchronization

 enables us to restrict the interleaving of executions

 Note: this also applies to processes, not just threads
 It also applies across machines in a distributed system

Example of Threads Accessing

Another Thread’s Stack

**char ptr; / global /

**int main() { int i; pthread_t tid; char msgs[2] = { "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 stack
indirectly through global ptr variable

Shared Variable Analysis

 VariableWhich variables are shared?^ Referenced by^ Referenced by^ Referenced by

instance main thread? peer thread 0? peer thread 1?
ptr yes yes yes
svar no yes yes
i.m yes no no
msgs.m yes yes yes
myid.p0 no yes no
myid.p1 no no yes

 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.

badcnt.c: An Improperly Synchronized

Threaded Program

unsigned int cnt = 0; / shared / #define NITERS 100000000 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)NITERS2) 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> ./badcnt BOOM! cnt=

linux> ./badcnt BOOM! cnt=

linux> ./badcnt BOOM! cnt=

cnt should be

equal to 200,000,000.

What went wrong?!

Concurrent Execution

 Key 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

H 1 L 1 U 1 S 1 H 2 L 2 U 2 S 2 T 2 T 1

1 1 1 1 2 2 2 2 2 1

  • 0 1 1 - - - - - 1 0 0 0 1 1 1 1 2 2 2

i (thread) (^) instri %eax 1 cnt

OK
          • 1 2 2 2 -

%eax 2

Concurrent Execution (cont)

 Incorrect ordering: two threads increment the counter, but the

result is 1 instead of 2.

H 1 L 1 U 1 H 2 L 2 S 1 T 1 U 2 S 2 T 2

1 1 1 2 2 1 1 2 2 2

  • 0 1 - - 1 1 - - - 0 0 0 0 0 1 1 1 1 1

i (thread) (^) instri %eax 1 cnt

        • 0 - - 1 1 1

%eax 2

Oops!

Progress Graphs

A progress graph depicts
the discrete execution
state space of concurrent
threads.
Each axis corresponds to
the sequential order of
instructions in a thread.
Each point corresponds to
a possible execution state
(Inst 1 , Inst 2 ).
E.g., (L 1 , S 2 ) denotes state
where thread 1 has
completed L 1 and thread
H 1 L 1 U 1 S 1 T 1 2 has completed S 2.

H 2

L 2

U 2

S 2

T 2

Thread 1

Thread 2

(L 1 , S 2 )

Trajectories in Progress Graphs

A trajectory is a sequence
of legal state transitions
that describes one possible
concurrent execution of
the threads.
Example:
H1, L1, U1, H2, L2,
S1, T1, U2, S2, T

H 1 L 1 U 1 S 1 T 1

H 2

L 2

U 2

S 2

T 2

Thread 1

Thread 2

Safe and Unsafe Trajectories

Def: A trajectory is safe
iff it doesn’t touch any
part of an unsafe region.
Claim: A trajectory is
correct (wrt cnt ) iff it is
safe.

H 1 L 1 U 1 S 1 T 1

H 2

L 2

U 2

S 2

T 2

Thread 1

Thread 2

Unsafe region (^) Unsafe trajectory

Safe trajectory

critical section wrt cnt

critical section wrt cnt

The classic example

 Suppose we have to implement a function to withdraw money from a
bank account:

int withdraw(account, amount) {

int balance = get_balance(account);

balance -= amount; put_balance(account, balance);

return balance;

}

 Now suppose a husband and wife share a bank account with a balance
of $100.

 what happens if you both go to separate ATM machines, and simultaneously withdraw $10.00 from the account?