Traditional View of a Process process context code

  • Slides: 21
Download presentation
Traditional View of a Process = process context + code, data, and stack Process

Traditional View of a Process = process context + code, data, and stack Process context Program context: Data registers Condition codes Stack pointer (SP) Program counter (PC) Code, data, and stack SP shared libraries brk run-time heap read/write data Kernel context: VM structures Descriptor table brk pointer – 1– PC read-only code/data 0 15 -213, F’ 02

Alternate View of a Process = thread + code, data, and kernel context Thread

Alternate View of a Process = thread + code, data, and kernel context Thread (main thread) Code and Data shared libraries SP stack Thread context: Data registers Condition codes Stack pointer (SP) Program counter (PC) brk run-time heap read/write data PC read-only code/data 0 Kernel context: VM structures Descriptor table brk pointer – 2– 15 -213, F’ 02

A Process With Multiple Threads Multiple threads can be associated with a process n

A Process With Multiple Threads Multiple threads can be associated with a process n n n 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) Thread 1 (main thread) Shared code and data Thread 2 (peer thread) shared libraries stack 1 stack 2 run-time heap read/write data Thread 1 context: Data registers Condition codes SP 1 PC 1 read-only code/data 0 Kernel context: VM structures Descriptor table brk pointer – 3– Thread 2 context: Data registers Condition codes SP 2 PC 2 15 -213, F’ 02

Logical View of Threads associated with a process form a pool of peers. n

Logical View of Threads associated with a process form a pool of peers. n Unlike processes which form a tree hierarchy Threads associated with process foo Process hierarchy P 0 T 2 T 4 T 1 P 1 shared code, data and kernel context sh T 5 – 4– sh sh T 3 foo bar 15 -213, F’ 02

Concurrent Thread Execution Two threads run concurrently (are concurrent) if their logical flows overlap

Concurrent Thread Execution Two threads run concurrently (are concurrent) if their logical flows overlap in time. Otherwise, they are sequential. Thread A Examples: n n Thread B Thread C Concurrent: A & B, A&C Sequential: B & C Time – 5– 15 -213, F’ 02

Threads vs. Processes How threads and processes are similar n Each has its own

Threads vs. Processes How threads and processes are similar n Each has its own logical control flow. n Each can run concurrently. Each is context switched. n How threads and processes are different n n Threads share code and data, processes (typically) do not. Threads are somewhat less expensive than processes. l Process control (creating and reaping) is twice as expensive as thread control. l Linux/Pentium III numbers: » ~20 K cycles to create and reap a process. » ~10 K cycles to create and reap a thread. – 6– 15 -213, F’ 02

The Pthreads "hello, world" Program /* * hello. c - Pthreads "hello, world" program

The Pthreads "hello, world" Program /* * hello. c - Pthreads "hello, world" program */ #include "csapp. h" Thread attributes (usually NULL) void *thread(void *vargp); int main() { pthread_t tid; Thread arguments (void *p) Pthread_create(&tid, NULL, thread, NULL); Pthread_join(tid, NULL); exit(0); } /* thread routine */ void *thread(void *vargp) { printf("Hello, world!n"); return NULL; } – 7– return value (void **p) 15 -213, F’ 02

Execution of Threaded“hello, world” main thread call Pthread_create() returns call Pthread_join() main thread waits

Execution of Threaded“hello, world” main thread call Pthread_create() returns call Pthread_join() main thread waits for peer thread to terminate peer thread printf() return NULL; (peer thread terminates) Pthread_join() returns exit() terminates main thread any peer threads – 8– 15 -213, F’ 02

Pros and Cons of Thread-Based Designs + Easy to share data structures between threads

Pros and Cons of Thread-Based Designs + Easy to share data structures between threads n e. g. , logging information, file cache. + Threads are more efficient than processes. --- Unintentional sharing can introduce subtle and hardto-reproduce errors! n – 9– The ease with which data can be shared is both the greatest strength and the greatest weakness of threads. 15 -213, F’ 02

Shared Variables in Threaded C Programs Question: Which variables in a threaded C program

Shared Variables in Threaded C Programs Question: Which variables in a threaded C program are shared variables? n The answer is not as simple as “global variables are shared” and “stack variables are private”. Requires answers to the following questions: n n n – 10 – What is the memory model for threads? How are variables mapped to memory instances? How many threads reference each of these instances? 15 -213, F’ 02

Threads Memory Model Conceptual model: n n Each thread runs in the context of

Threads Memory Model Conceptual model: n n Each thread runs in the context of a process. Each thread has its own separate thread context. l Thread ID, stack pointer, program counter, condition codes, and general purpose registers. n All threads share the remaining process context. l Code, data, heap, and shared library segments of the process virtual address space. l Open files and installed handlers Operationally, this model is not strictly enforced: n n 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. – 11 – 15 -213, F’ 02

Thread Safety Functions called from a thread must be thread-safe. We identify four (non-disjoint)

Thread Safety Functions called from a thread must be thread-safe. We identify four (non-disjoint) classes of thread-unsafe functions: n n – 12 – 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. 15 -213, F’ 02

Thread-Unsafe Functions Class 1: Failing to protect shared variables. – 13 – n Fix:

Thread-Unsafe Functions Class 1: Failing to protect shared variables. – 13 – n Fix: Use semaphore operations. n Issue: Synchronization operations will slow down code. 15 -213, F’ 02

Thread-Unsafe Functions (cont) Class 2: Relying on persistent state across multiple function invocations. n

Thread-Unsafe Functions (cont) Class 2: Relying on persistent state across multiple function invocations. n n 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; } – 14 – 15 -213, F’ 02

Thread-Unsafe Functions (cont) Class 3: Returning a ptr to a static variable. Fixes: n

Thread-Unsafe Functions (cont) Class 3: Returning a ptr to a static variable. Fixes: n 1. Rewrite code so caller passes pointer to struct. » Issue: Requires changes in caller and callee. n 2. Lock-and-copy » Issue: Requires only simple changes in caller (and none in callee) » However, caller must free memory. – 15 – struct hostent *gethostbyname(char name) { static struct hostent h; <contact DNS and fill in h> return &h; } hostp = Malloc(. . . )); gethostbyname_r(name, hostp); struct hostent *gethostbyname_ts(char *p) { struct hostent *q = Malloc(. . . ); P(&mutex); /* lock */ p = gethostbyname(name); *q = *p; /* copy */ V(&mutex); return q; } 15 -213, F’ 02

Thread-Unsafe Functions Class 4: Calling thread-unsafe functions. – 16 – n Calling one thread-unsafe

Thread-Unsafe Functions Class 4: Calling thread-unsafe functions. – 16 – n Calling one thread-unsafe function makes an entire function thread-unsafe. n Fix: Modify the function so it calls only thread-safe functions 15 -213, F’ 02

Reentrant Functions A function is reentrant iff it accesses NO shared variables when called

Reentrant Functions A function is reentrant iff it accesses NO shared variables when called from multiple threads. n Reentrant functions are a proper subset of the set of thread-safe functions. All functions Thread-safe functions Reentrant functions n – 17 – Thread-unsafe functions NOTE: The fixes to Class 2 and 3 thread-unsafe functions require modifying the function to make it reentrant. 15 -213, F’ 02

Thread-Safe Library Functions All functions in the Standard C Library (at the back of

Thread-Safe Library Functions All functions in the Standard C Library (at the back of your K&R text) are thread-safe. n Examples: malloc, free, printf, scanf Most Unix system calls are thread-safe, with a few exceptions: Thread-unsafe function Class asctime 3 gethostbyaddr 3 gethostbyname 3 inet_ntoa 3 localtime 3 rand 2 – 18 – Reentrant version asctime_r gethostbyaddr_r gethostbyname_r (none) localtime_r rand_r 15 -213, F’ 02

Races A race occurs when the correctness of the program depends on one thread

Races 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); } – 19 – /* thread routine */ void *thread(void *vargp) { int myid = *((int *)vargp); printf("Hello from thread %dn", myid); return NULL; } 15 -213, F’ 02

Deadlock Thread 2 deadlock state V(s) forbidden region for s Any trajectory that enters

Deadlock Thread 2 deadlock state V(s) forbidden region for s Any trajectory that enters the deadlock region will eventually reach the deadlock state, waiting for either s or t to become nonzero. V(t) P(s) deadlock region forbidden region for t P(t) Other trajectories luck out and skirt the deadlock region. P(s) Initially, s=t=1 – 20 – Locking introduces the potential for deadlock: waiting for a condition that will never be true. P(t) V(s) V(t) Thread 1 Unfortunate fact: deadlock is often non-deterministic. 15 -213, F’ 02

Threads Summary Threads provide another mechanism for writing concurrent programs. Threads are growing in

Threads Summary Threads provide another mechanism for writing concurrent programs. Threads are growing in popularity n n Somewhat cheaper than processes. Easy to share data between threads. However, the ease of sharing has a cost: n n Easy to introduce subtle synchronization errors. Tread carefully with threads! For more info: n – 21 – D. Butenhof, “Programming with Posix Threads”, Addison. Wesley, 1997. 15 -213, F’ 02