310 likes | 488 Views
Thread 15213-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
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