concurrent programming
DESCRIPTION
Concurrent Programming. Outline. Topics: Shared variables Synchronizing with semaphores Suggested reading: 12.4~12.5. Approaches to Concurrency. Processes Hard to share resources: easy to avoid unintended sharing High overhead in adding/removing clients Threads - PowerPoint PPT PresentationTRANSCRIPT
1
Concurrent Programming
2
Outline
• Topics:– Shared variables
– Synchronizing with semaphores
• Suggested reading:– 12.4~12.5
Approaches to Concurrency
• ProcessesProcesses– Hard to share resources: easy to avoid unintended sharing– High overhead in adding/removing clients
• ThreadsThreads– Easy to share resources: Perhaps too easy– Medium overhead– Not much control over scheduling policies– Difficult to debug: event orderings not repeatable
• I/O MultiplexingI/O Multiplexing– Tedious and low level– Total control over scheduling– Very low overhead– Cannot create as fine grained a level of concurrency– Does not make use of multi-core
4
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
5
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
6
A process with multiple threads
• Multiple 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)
7
A process with multiple threads
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)
Logical View of Threads
• Threads associated with process form a pool of peers– Unlike processes which form a tree hierarchy
P1
sh sh sh
foo
bar
T1
Process hierarchyThreads associated with process foo
T2T4
T5 T3
shared code, dataand kernel context
P0
9
Pros and cons of 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!– The ease with which data can be shared is
both the greatest strength and the greatest weakness of threads
– Hard to know which data shared & with private
10
Shared variables in threaded C programs
• Which variables in a C program are shared or not?– What is the memory model for threads?
– How are instances of the variable mapped to memory?
– How many threads reference each of these instances?
11
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
12
Threads memory model
• 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.
The MISMATCH between the CONCEPTUAL and OPERATION MODEL is a source of confusion and errors
13
Shared variable analysis
1 #include "csapp.h"
2 #define N 2
3 void *thread(void *vargp);
4
5 char **ptr; /* global variable */
6
14
Shared variable analysis
7 int main()
8 {
9 int i;
10 pthread_t tid;
11 char *msgs[N] = {
12 "Hello from foo",
13 "Hello from bar"
14 };
15
16 ptr = msgs;
17 for (i = 0; i < N; i++)
18 Pthread_create(&tid, NULL, thread, (void *)i);
19 Pthread_exit(NULL);
20 }
1 #include "csapp.h"2 #define N 23 void *thread(void *vargp);45 char **ptr; 6 /* global variable */
15
Shared variable analysis
21 void *thread(void *vargp)
22 {
23 int myid = (int)vargp;
24 static int cnt = 0;
25
26 printf("[%d]:%s(cnt=%d)\n", myid, ptr[myid], ++cnt);
27 }
Mapping Variable Instances to Memory
• Global variables– Def: Variable declared outside of a function– Virtual memory contains exactly one instance of any
global variable
• Local variables– Def: Variable declared inside function without static
attribute– Each thread stack contains one instance of each local
variable
• Local static variables– Def: Variable declared inside function with the static
attribute– Virtual memory contains exactly one instance of any local
static variable.
17
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 yescnt no yes yesi.m yes no nomsgs.m yes yes yesmyid.p0 no yes nomyid.p1 no no yes
18
Shared variable analysis
• Answer: A variable x is shared iff multiple threads reference at least one instance of x
• Thus:– ptr, cnt, and msgs are shared.– i and myid are NOT shared.
19
Shared variable analysis
9 int main()10 {11 pthread_t tid1, tid2;1213 Pthread_create(&tid1, NULL, count, NULL);14 Pthread_create(&tid2, NULL, count, NULL);15 Pthread_join(tid1, NULL);16 Pthread_join(tid2, NULL);1718 if (cnt != (unsigned)NITERS*2)19 printf("BOOM! cnt=%d\n", cnt);20 else21 printf("OK cnt=%d\n", cnt);22 exit(0);23 }
1 #include "csapp.h"23 #define NITERS 1000000004 void *count(void *arg);56 /* shared variable */7 unsigned int cnt = 0;8
20
Shared variable analysis
24
25 /* thread routine */
26 void *count(void *arg)
27 {
28 int i;
29 for (i=0; i<NITERS; i++)
30 cnt++;
31 return NULL;
32 }
21
Shared variable analysis
• cnt should be equal to 200,000,000. • What went wrong?!
linux> badcntBOOM! cnt=198841183
linux> badcntBOOM! cnt=198261801
linux> badcntBOOM! cnt=198269672
22
for (i=0; i<NITERS; i++)for (i=0; i<NITERS; i++) cnt++;cnt++;
C code for thread i
Assembly code for counter loop
23
.L9:movl -4(%ebp),%eax #i:-4(%ebp)cmpl $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:
Asm code for thread i
Head (Hi)
Tail (Ti)
Load cnt (Li)Update cnt (Ui)Store cnt (Si)
Assembly code for counter loop
24
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
25
Concurrent execution
H1
L1
U1
S1
H2
L2
U2
S2
T2
T1
1111222221
-011-
-
-
-
-
1
0001111222
i(thread) instri cnt%eax1
OK
----
-
1222-
%eax2
26
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
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 cnt%eax1
-
-
-
-
-
-
1
1
1
%eax2
0
27
A 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)
Progress graphs
28
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
Trajectories in progress graphs
29
L, U, and S form a critical section withrespect to the sharedvariable cnt.
Instructions in criticalsections (write 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
Critical sections and unsafe regions
30
Def: A trajectory is safe iff it doesn’t touch any part of an unsafe region.
Claim: A trajectory is correct (write cnt) iff it is safe.
critical section wrt cnt
H1 L1 U1 S1 T1
H2
L2
U2
S2
T2
Thread 1
Thread 2
Unsafe region Unsafetrajectory
Safe trajectory
critical section wrt cnt
Safe and unsafe trajectories
31
Synchronizing with semaphores
• Dijkstra's P and V operations on
semaphores
– semaphoresemaphore: non-negative integer
synchronization variable.
• P(s): [ while (s == 0) wait(); s--; ]
– Dutch for "Proberen" (test)
• V(s): [ s++; ]
– Dutch for "Verhogen" (increment)
32
Synchronizing with semaphores
• Dijkstra's P and V operations on
semaphores
– OS guarantees that operations between
brackets [ ] are executed indivisibly.
• Only one P or V operation at a time can modify s.
• When while loop in P terminates, only that P can
decrement s.
• Semaphore invariant: (s >= 0)
33
#include <semaphore.h>
int sem_init(sem_t *sem, 0, unsigned int value);int sem_wait(sem_t *s); /* P(s) */int sem_post(sem_t *s); /* V(s) */
#include “csapp.h”
void P(sem_t *s); /* Wrapper function for sem_wait */void V(sem_t *s); /* Wrapper function for sem_wait */
POSIX semaphores
34
#include "csapp.h"#define NITERS 10000000unsigned int cnt; /* counter */sem_t sem; /* semaphore */
int main() { pthread_t tid1, tid2; Sem_init(&sem, 0, 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);}
Sharing with POSIX semaphores
35
/* thread routine */void *count(void *arg){ int i;
for (i=0; i<NITERS; i++) { P(&sem); cnt++; V(&sem); } return NULL;}
Sharing with POSIX semaphores
36
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 a 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 regionForbidden 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
Safe sharing with semaphores