310 likes | 328 Views
This resource explores the thread memory model, system calls, pitfalls of using threads, semaphore final forms, and evaluation of pthread interfaces for web servers and browsers. Learn about the importance of concurrency, shared data, thread safety, and implementations. Dive into Posix Threads (Pthreads) interface for creating, terminating threads, managing thread IDs, synchronizing shared variables, and thread safety practices. The included "hello, world" program illustrates thread creation and termination. Understand the differences between joinable and detached threads, and how to protect shared variables in a concurrent system.
E N D
Thread15213-S04, Recitation, Section A Thread Memory Model Thread Interfaces (System Calls) Thread Safety (Pitfalls of Using Thread) Racing Semaphore Final & Evaluation Forms
pthread_create • pthread_join • pthread_self • pthread_cancel • pthread_exit • pthread_mutex_init • pthread_mutex_[un]lock • pthread_cond_init • pthread_cond_[timed]wait
Web Server Web Browser Web Server Proxy Web Browser Web Browser Web Server Why Do We Care About Thread • Useful for L7 Part II • A very important way to implement modern concurrent systems • What’s concurrency?
Three Methods to Implement Concurrency • 1. Processes • Fork a child process for every incoming client connection • Difficult to share data among child processes • 2. Threads • Create a thread to handle every incoming client connection • Our focus today • 3. I/O multiplexing with Unix select() • Use select() to notice pending socket activity • Manually interleave the processing of multiple open connections • More complex! • ~ implementing your own app-specific thread package!
View of Process • Process = process context + code, data, and stack Process context Code, data, and stack stack SP Program context: Data registers Condition code Stack pointer (SP) Program counter (PC) Kernel context: VM structures Descriptor table shared libraries run-time heap read/write data PC read-only code/data 0
Thread memory model Thread 1 (main thread) Thread 2 (peer thread) stack 1 stack 2 Thread 1 context: Data registers Condition code SP1 PC1 Thread 2 context: Data registers Condition code SP2 PC2 View of Thread • Multiple threads can be associated with a process • Each thread has its own logical control flow (instruction flow) • Each thread has its own thread ID (TID) • Each thread shares the same code, data, and kernel context Shared code and data shared libraries run-time heap read/write data read-only code/data 0 Kernel context: VM structures Descriptor table
Posix Threads (Pthreads) Interface • Standard interface for ~60 functions • Creating and reaping threads. • pthread_create • pthread_join • Determining your thread ID • pthread_self • Terminating threads • pthread_cancel • pthread_exit • Synchronizing access to shared variables • pthread_mutex_init • pthread_mutex_[un]lock • pthread_cond_init • pthread_cond_[timed]wait
The Pthread "hello, world" Program /* * hello.c - Pthreads "hello, world" program */ #include "csapp.h" /* thread routine */ void *thread(void *vargp) { printf("Hello, world!\n"); return NULL; } int main() { pthread_t tid; Pthread_create(&tid, NULL, thread, NULL); Pthread_join(tid, NULL); exit(0); }
main thread Call Pthread_create() Pthread_create() returns peer thread return NULL; (peer thread terminates) Pthread_join() returns Execution of Threaded“hello, world” call Pthread_join() printf() main thread waits for peer thread to terminate exit() terminates main thread and any peer threads
Practices • Basic usage of thread • Pthread_exit() & exit() • Joinable and detached thread • Thread safety • Protecting shared variable • Function that returns a static pointer • (more) ……
pthread_exit() & exit() • Program 1.1 void *thread(void *vargp){ pthread_exit((void*)42);}int main(){ int i; pthread_t tid; pthread_create(&tid, NULL, thread, NULL); pthread_join(tid, (void **)&i); printf("%d\n",i);}
pthread_exit() & exit() • Program 1.2 void *thread(void *vargp){ exit(42);}int main(){ int i; pthread_t tid; pthread_create(&tid, NULL, thread, NULL); pthread_join(tid, (void **)&i); printf("%d\n",i);}
pthread_exit() & exit() • pthread_exit() only terminates the current thread, NOT the process • Exit() terminates all the threads in the process, i.e., the process itself
Practices • Basic usage of thread • Pthread_exit() & exit() • Joinable and detached thread • Thread safety • Protecting shared variable • Function that returns a static pointer • (more) ……
Joinable & Detached Threads • At any point in time, a thread is either joinable or detached. • Joinable thread can be reaped and killed by other threads. • must be reaped (with pthread_join) to free memory resources. • Detached thread cannot be reaped or killed by other threads. • resources are automatically reaped on termination. • Default state is joinable. • use pthread_detach(pthread_self()) to make detached.
Practices • Basic usage of thread • Pthread_exit() & exit() • Joinable and detached thread • Thread safety • Protecting shared variable • Function that returns a static pointer • (more) ……
Protecting shared variables • Program 1.5 int i = 42;void *thread(void *vargp){ printf("%d\n",i); }void *thread2(void *vargp){ i = 31; }int main(){ pthread_t tid, tid2; pthread_create(&tid2, NULL, thread2, (void*)&i); pthread_create(&tid, NULL, thread, (void*)&i); pthread_join(tid, (void**)&i); pthread_join(tid2, NULL);}
Practices • Basic usage of thread • Pthread_exit() & exit() • Joinable and detached thread • Thread safety • Protecting shared variable • Function that returns a static pointer • (more) ……
Functions that return a pointer to a static value int main () { struct in_addr a; a.s_addr = inet_addr(“1.1.1.1”); printf(“%s\n”, inet_ntoa(a)); } Output: 1.1.1.1 int main () { struct in_addr a, b; a.s_addr = inet_addr(“1.1.1.1”); b.s_addr = inet_addr(“2.2.2.2”); printf(“%s %s\n”, inet_ntoa(a), inet_ntoa(b)); } output: ???
Thread Safety • Class 1: Functions that do not protect shared variables • Class 2: Functions that keep state across multiple invocations • rand() • Textbook P. 886 • Class 3: Functions that return a pointer to a static variable • Class 4: Functions that call thread-unsafe functions • May or may not be thread-unsafe • Textbook P.887
More Practice Problems • Program 1.3 & 1.4 are left for your practice
Racing • A race occurs when the correctness of a program depends on one thread reaching point x in its control flow before another thread reaches point y. • Generally related with the access to the shared variables • Need synchronization • Ways to do synchronization: • Semaphores • Mutual-exclusion
Program 2.b void *foo(void *vargp) { int id; id = *((int *)vargp); printf("Thread %d\n", id);}int main() { pthread_t tid[2]; int i; for (i = 0; i < 2; i++) Pthread_create(&tid[i], NULL, foo, &i); Pthread_join(tid[0], NULL); Pthread_join(tid[1], NULL);} Racing!
Program 2.a void *foo(void *vargp) { int myid; myid = *((int *)vargp); Free(vargp); printf("Thread %d\n", myid);}int main() { pthread_t tid[2]; int i, *ptr; for (i = 0; i < 2; i++) { ptr = Malloc(sizeof(int)); *ptr = i; Pthread_create(&tid[i], 0, foo, ptr); } Pthread_join(tid[0], 0); Pthread_join(tid[1], 0);} Good!
Program 2.c void *foo(void *vargp) { int id; id = (int)vargp; printf("Thread %d\n", id);}int main() { pthread_t tid[2]; int i; for (i = 0; i < 2; i++) Pthread_create(&tid[i], 0, foo, i); Pthread_join(tid[0], 0); Pthread_join(tid[1], 0);} Good!
The general solution for racing • Semaphore & mutual-exclusion • Mutex is a special case for the problems that semaphore targets to solve, and thus can be implemented using semaphore • But mutex seems to be more popularly used (probably because more people understand it) • Classic solution: Dijkstra's P and V operations on semaphores. • semaphore: non-negative integer synchronization variable. • P(s): [ while (s == 0) wait(); s--; ] • V(s): [ s++; ] • 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 decrements. • Semaphore invariant: (s >= 0)
Program 2.d sem_t s; /* semaphore s */void *foo(void *vargp) { int id; id = *((int *)vargp); V(&s); printf("Thread %d\n", id);}int main() { pthread_t tid[2]; int i; sem_init(&s, 0, 0); /* S=0 INITIALLY */ for (i = 0; i < 2; i++) { Pthread_create(&tid[i], 0, foo, &i); P(&s); } Pthread_join(tid[0], 0); Pthread_join(tid[1], 0);} Good!
Program 2.e sem_t s; /* semaphore s */void *foo(void *vargp) { int id; P(&s); id = *((int *)vargp); V(&s); printf("Thread %d\n", id);}int main() { pthread_t tid[2]; int i; sem_init(&s, 0, 1); /* S=1 INITIALLY */ for (i = 0; i < 2; i++) { Pthread_create(&tid[i], 0, foo, &i); } Pthread_join(tid[0], 0); Pthread_join(tid[1], 0);} Racing!
Summary So Far • Thread • Thread memory model • How to write thread programs • Thread safety (pitfalls of using thread) • Racing • Semaphore
Final • Times • Exam Time: May 3rd (Monday) 5:30pm – 8:30p UC McConomy • Review Session: May 1st (Saturday), 3:00pm
Evaluation Forms • There are questions on both sides • One student bring them to WH 5101