View
231
Download
0
Tags:
Embed Size (px)
Citation preview
– 1 – 15-213, F’02
Traditional View of a ProcessTraditional 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
– 2 – 15-213, F’02
Alternate View of a ProcessAlternate 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
– 3 – 15-213, F’02
A Process With Multiple ThreadsA 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)
– 4 – 15-213, F’02
Logical View of ThreadsLogical 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
– 5 – 15-213, F’02
Concurrent Thread ExecutionConcurrent Thread Execution
Two threads run concurrently (are concurrent) if their logical flows overlap in time.
Otherwise, they are sequential.
Examples: Concurrent: A & B, A&C Sequential: B & C
Time
Thread A Thread B Thread C
– 6 – 15-213, F’02
Threads vs. ProcessesThreads 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.
– 7 – 15-213, F’02
The Pthreads "hello, world" ProgramThe Pthreads "hello, world" Program/* * hello.c - Pthreads "hello, world" program */#include "csapp.h"
void *thread(void *vargp);
int main() { pthread_t tid;
Pthread_create(&tid, NULL, thread, NULL); Pthread_join(tid, NULL); exit(0);}
/* thread routine */void *thread(void *vargp) { printf("Hello, world!\n"); return NULL;}
Thread attributes (usually NULL)
Thread arguments(void *p)
return value(void **p)
– 8 – 15-213, F’02
Execution of Threaded“hello, world”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
– 9 – 15-213, F’02
Pros and Cons of Thread-Based DesignsPros 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.
– 10 – 15-213, F’02
Shared Variables in Threaded C ProgramsShared Variables in Threaded C ProgramsQuestion: Which variables in a threaded C program are
shared variables? The answer is 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?
– 11 – 15-213, F’02
Threads Memory ModelThreads 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.
– 12 – 15-213, F’02
Thread SafetyThread 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 a pointer to a static variable. Class 4: Calling thread-unsafe functions.
– 13 – 15-213, F’02
Thread-Unsafe FunctionsThread-Unsafe Functions
Class 1: Failing to protect shared variables. Fix: Use semaphore operations. Issue: Synchronization operations will slow down code.
– 14 – 15-213, F’02
Thread-Unsafe Functions (cont)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; }
– 15 – 15-213, F’02
Thread-Unsafe Functions (cont)Thread-Unsafe Functions (cont)Class 3: Returning a ptr to
a 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;}
– 16 – 15-213, F’02
Thread-Unsafe FunctionsThread-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
– 17 – 15-213, F’02
Reentrant FunctionsReentrant 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.
Reentrantfunctions
All functions
Thread-unsafefunctions
Thread-safefunctions
– 18 – 15-213, F’02
Thread-Safe Library FunctionsThread-Safe Library Functions
All functions in the Standard C Library (at the back of your K&R text) are thread-safe. Examples: malloc, free, printf, scanf
Most Unix system calls are thread-safe, with a few exceptions:
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
– 19 – 15-213, F’02
RacesRaces
A race occurs when the correctness of the program 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;}
– 20 – 15-213, F’02
deadlockregion
DeadlockDeadlock
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 introduces thepotential for deadlock: waiting for a condition that will never be true.
Any trajectory that entersthe deadlock region willeventually reach thedeadlock state, waiting for either s or t to become nonzero.
Other trajectories luck out and skirt the deadlock region.
Unfortunate fact: deadlock is often non-deterministic.
– 21 – 15-213, F’02
Threads SummaryThreads 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.