Download presentation
Presentation is loading. Please wait.
1
Concurrent Programming
2
Outline Topics: Suggested reading: Shared variables
Synchronizing with semaphores Suggested reading: 12.4~12.5
3
A process with multiple threads
shared libraries run-time heap read/write data Thread 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: SP2 PC2 stack 2 Thread 2 (peer thread)
4
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?
5
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
6
Operationally, this model is not strictly enforced:
Threads memory model Operationally, this model is not strictly enforced: Register values are truly separate and protected. However, 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
7
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++) Pthread_create(&tid, NULL, thread, (void *)i); 19 Pthread_exit(NULL); 20 } 1 #include "csapp.h" 2 #define N 2 3 void *thread(void *vargp); 4 5 char **ptr; 6 /* global variable */
8
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 }
9
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.
10
Shared variable analysis
Which variables are shared? Variable Referenced by Referenced by Referenced by instance main thread? peer thread-0? peer thread-1? ptr yes yes yes cnt no yes yes i.m yes no no msgs.m yes yes yes myid.p0 no yes no myid.p1 no no yes
11
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.
12
Shared variable analysis
1 #include "csapp.h" 2 3 #define NITERS 4 void *count(void *arg); 5 6 /* shared variable */ 7 unsigned int cnt = 0; 8 Shared variable analysis 9 int main() 10 { 11 pthread_t tid1, tid2; 12 13 Pthread_create(&tid1, NULL, count, NULL); 14 Pthread_create(&tid2, NULL, count, NULL); 15 Pthread_join(tid1, NULL); 16 Pthread_join(tid2, NULL); 17 18 if (cnt != (unsigned)NITERS*2) printf("BOOM! cnt=%d\n", cnt); 20 else printf("OK cnt=%d\n", cnt); 22 exit(0); 23 }
13
Shared variable analysis
24 25 /* thread routine */ 26 void *count(void *arg) 27 { 28 int i; 29 for (i=0; i<NITERS; i++) cnt++; 31 return NULL; 32 }
14
Shared variable analysis
linux> badcnt BOOM! cnt= BOOM! cnt= BOOM! cnt= cnt should be equal to 200,000,000. What went wrong?!
15
Assembly code for counter loop
C code for thread i for (i=0; i<NITERS; i++) cnt++;
16
Assembly code for counter loop
Asm code for thread i movq (%rdi),%rcx #i:-4(%ebp) testq %rcx,%rcx jle .L2 movl $0, %eax .L3: movq cnt(%rip),%rdx # Load addq %rdx # Update movq %rdx,cnt(%rip) # Store addq $1,%rax cmpq %rcx,%rax jne .L3 .L2: Head (Hi) Load cnt (Li) Update cnt (Ui) Store cnt (Si) Tail (Ti)
17
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
18
Concurrent execution H1 L1 U1 S1 H2 L2 U2 S2 T2 T1 1 2 - i(thread)
i(thread) instri cnt %rdx1 OK %rdx2
19
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 2 - i(thread) instri cnt %rdx1 %rdx2
20
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 (Inst1, Inst2). E.g., (L1, S2) denotes state where thread 1 has completed L1 and thread 2 has completed S2. H1 L1 U1 S1 T1 H2 L2 U2 S2 T2 Thread 1 Thread 2 (L1, S2)
21
Trajectories in progress graphs
L1 U1 S1 T1 H2 L2 U2 S2 T2 Thread 1 Thread 2 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, T2
22
Critical sections and unsafe regions
H1 L1 U1 S1 T1 H2 L2 U2 S2 T2 Thread 1 Thread 2 Unsafe region critical section wrt cnt L, U, and S form a critical section with respect to the shared variable cnt. Instructions in critical sections (write to some shared variable) should not be interleaved. Sets of states where such interleaving occurs form unsafe regions.
23
critical section wrt cnt
Safe and unsafe trajectories critical section wrt cnt H1 L1 U1 S1 T1 H2 L2 U2 S2 T2 Thread 1 Thread 2 Unsafe region Unsafe trajectory Safe trajectory 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.
24
Synchronizing with semaphores
Dijkstra's P and V operations on semaphores semaphore: non-negative integer synchronization variable. P(s): [ while (s == 0) wait(); s--; ] Dutch for "Proberen" (test) V(s): [ s++; ] Dutch for "Verhogen" (increment)
25
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)
26
POSIX semaphores #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 */
27
Sharing with POSIX semaphores
#include "csapp.h" #define NITERS unsigned 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); }
28
Sharing with POSIX semaphores
/* thread routine */ void *count(void *arg) { int i; for (i=0; i<NITERS; i++) { P(&sem); cnt++; V(&sem); } return NULL;
29
Safe sharing with semaphores
P(s) V(s) T1 Thread 1 Thread 2 L1 U1 S1 H2 T2 L2 U2 S2 Unsafe region Forbidden region 1 -1 Initially s = 1 Provide mutually exclusive access to shared variable by surrounding critical section with P and V operations on semaphore s (initially set to 1). Semaphore invariant creates a forbidden region that encloses unsafe region and is never touched by any trajectory. Mutual exclusion
Similar presentations
© 2024 SlidePlayer.com Inc.
All rights reserved.