Computer Systems Introduction to Threads Race Conditions Recap





















- Slides: 21
Computer Systems Introduction to Threads Race Conditions
Recap: Memory Layout of a Unix Process 0 High Memory Address Text (machine code) Data (initialized global variables) BSS (uninitialized global variables) Heap (dynamically allocated memory) Stack (local variables)
Single and Multi-Threaded Processes
Single- vs. Multi-Threaded Processes Process Thread Process Memory Heap Stack Data Code single-threaded Thread Stack multi-threaded
What are Threads? q A thread is an independent stream of instructions - Basic unit of CPU utilization q A thread has its own - thread ID - execution stack q A thread shares with its sibling threads - The code, data and heap section - Other OS resources, such as open files
Address Space (Virtual Memory) Physical Memory Heap Process 1 Stack TLB C A C H E CPU (aka Core) PC, SP Registers Global Variables Process 2 6
Address Space (VM) Heap Process 1 Stack Process 1 Physical Memory TLB Global Variables C A C H E CPU (aka Core) Saved PC, SP SP Registers Process 2 7
Address Space (VM) TLB Commo n Heap Thread 1 Physical Memory C A C H E CPU 1 (aka Core 1) PC, SP Registers Stack Thread Local Storage Thread 2 Stack Thread Local Storage Common Global Variables 8
Multi-Threaded Processes q Each thread has a private stack But threads share the process address space! q There is no memory protection! q Threads could potentially write into each other’s stack q
Why use Threads? q A specific example, a Web server: in an infinite loop { get web page request from client check if page exists and client has permissions create a thread to transmit web page back to client }
Concurrent thread execution on a single-core system Parallel thread execution on a dual-core system
pthreads q Refers to the POSIX standard (IEEE 1003. 1 c) q API for thread creation and synchronization q Common in UNIX operating systems
Java Threads q Java threads may be created by: - Extending Thread class - Implementing the Runnable interface q JVM manages Java threads - Creation - Execution - Etc.
BIG Issue: Shared Data, which leads to Race Conditions
An Example: badcnt. c #define NITERS 1000000 unsigned int cnt = 0; /* shared */ int main() { pthread_t tid 1, tid 2; pthread_create(&tid 1, Count, pthread_create(&tid 2, Count, NULL, NULL); pthread_join(tid 1, NULL); pthread_join(tid 2, NULL); if (cnt != (unsigned)NITERS*2) printf("BOOM! cnt=%dn", cnt); else printf("OK cnt=%dn", cnt); } /* thread routine */ void * Count(void *arg) { int i; for (i=0; i<NITERS; i++) cnt++; return NULL; } linux>. /badcnt BOOM! cnt=1988411 linux>. /badcnt BOOM! cnt=1982618 linux>. /badcnt BOOM! cnt=1982696 cnt should be equal to 2, 000. What went wrong? !
Critical Sections q Critical section = block of code that accesses shared data /* thread routine */ void * Count(void *arg) { int i; for (i=0; i<NITERS; i++) cnt++; /* global, shared */ return NULL; } q The statement cnt++ is non-atomic: at machine level, it translates into three machine instructions mov R, cnt interrupts) add R, 1 mov cnt, R ; atomic (no interrupts) ; atomic (no
Race Condition q First thread executes cnt++ implemented as register 1 = cnt register 1 = register 1 + 1 cnt = register 1 q Second thread executes cnt++ implemented as register 2 = cnt register 2 = register 2 + 1 cnt = register 2 q Consider this execution interleaving with “cnt = 5” initially: first thread executes register 1 = cnt {register 1 = 5} first thread executes register 1 = register 1 + 1 {register 1 = 6} Timer Interrupt second thread executes register 2 = cnt {register 2 = 5} second thread executes register 2 = register 2 + 1 {register 2 = 6} Timer Interrupt first thread executes cnt = register 1 {cnt = 6 } second thread executes cnt = register 2 {cnt = 6}
Race Conditions q Race Conditions - occur when several threads access shared data concurrently - the result may vary from one execution to the next q We’d like to execute this instruction atomically: cnt++; machine level R = cnt R = R + 1 cnt = R (An atomic operation completes without interruption) q Need some kind of mutual exclusion primitives - only a thread should ever enter a critical section (next lecture)
Practice Exercise q Consider two threads sharing a global variable count, with initial value equal to 10: Thread A count++; q Thread B count--; What are the possible values for count after both threads finish executing:
Practice Exercise q q Consider the following three concurrent threads that share a global variable g, initially 10: Thread A Thread B Thread C g = g * 2; g = g + 1; g = g - 2; What are the possible values for g, after all three threads finish executing?
Hands-on Session q Complete the hands-on POSIX programming exercises posted on the class website - Creating threads - Passing data to threads - pthread_create - pthread_exit - pthread_self - pthread_join - pthread_attach - pthread_detach