Presentation is loading. Please wait.

Presentation is loading. Please wait.

Concurrency Threads Synchronization Thread-safety of Library Functions Anubhav Gupta Dec. 2, 2002 Outline.

Similar presentations


Presentation on theme: "Concurrency Threads Synchronization Thread-safety of Library Functions Anubhav Gupta Dec. 2, 2002 Outline."— Presentation transcript:

1 Concurrency Threads Synchronization Thread-safety of Library Functions Anubhav Gupta Dec. 2, 2002 Outline

2 15213 RecitationAnubhav Gupta2 Important Dates Lab 7 Proxy: due on Thursday, Dec 5 Final Exam: Tuesday, Dec 17

3 15213 RecitationAnubhav Gupta3 Concurrent Servers Iterative servers can only serve one client at a time Concurrent servers are able to handle multiple requests in parallel Required by L7 Part II Web Browser Web Server Web Browser Web Browser Web Server Web Server Proxy

4 15213 RecitationAnubhav Gupta4 Three Ways for Creating Concurrent Servers 1. Processes –Fork a child process for every incoming client connection –Difficult to share data among child processes 2. 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 scheduler! 3. Threads –Create a thread to handle every incoming client connection –Our focus today

5 15213 RecitationAnubhav Gupta5 Traditional 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 stack SP PC brk Process context

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

7 15213 RecitationAnubhav Gupta7 A Process With Multiple Threads Multiple threads can be associated with a process –Each thread has its own logical control flow (instruction flow) –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 data Shared code and data read-only code/data Thread 1 context: Data registers Condition codes SP1 PC1 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)

8 15213 RecitationAnubhav Gupta8 Threads 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 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.

9 15213 RecitationAnubhav Gupta9 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 exit [terminates all threads], return [terminates current thread] –Synchronizing access to shared variables pthread_mutex_init pthread_mutex_[un]lock pthread_cond_init pthread_cond_[timed]wait

10 15213 RecitationAnubhav Gupta10 The 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) Upper case Pthread_xxx checks errors

11 15213 RecitationAnubhav Gupta11 Execution of Threaded“hello, world” main thread main thread waits for peer thread to terminate exit() terminates main thread and any peer threads peer thread call Pthread_create() call Pthread_join() Pthread_join() returns printf() return NULL; (peer thread terminates) Pthread_create() returns

12 15213 RecitationAnubhav Gupta12 Thread-Based Concurrent Echo Server int main(int argc, char **argv) { int listenfd, *connfdp, port, clientlen; struct sockaddr_in clientaddr; pthread_t tid; if (argc != 2) { fprintf(stderr, "usage: %s \n", argv[0]); exit(0); } port = atoi(argv[1]); listenfd = open_listenfd(port); while (1) { clientlen = sizeof(clientaddr); connfdp = Malloc(sizeof(int)); *connfdp = Accept(listenfd,(SA *)&clientaddr,&clientlen); Pthread_create(&tid, NULL, thread, connfdp); }

13 15213 RecitationAnubhav Gupta13 Thread-Based Concurrent Server (cont) * thread routine */ void *thread(void *vargp) { int connfd = *((int *)vargp); Pthread_detach(pthread_self()); Free(vargp); echo_r(connfd); /* thread-safe version of echo() */ Close(connfd); return NULL; } ?

14 15213 RecitationAnubhav Gupta14 Issue 1: 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.

15 15213 RecitationAnubhav Gupta15 Issue 2: Avoid Unintended Sharing For example, what happens if we pass the address of connfd to the thread routine as in the following code? connfdp = Malloc(sizeof(int)); *connfdp = Accept(listenfd,(SA *)&clientaddr,&clientlen); Pthread_create(&tid, NULL, thread, connfdp); connfd = Accept(listenfd,(SA *)&clientaddr,&clientlen); Pthread_create(&tid, NULL, thread, (void *)&connfd);

16 15213 RecitationAnubhav Gupta16 Issue 3: Thread-safe Easy to share data structures between threads But we need to do this correctly! Recall the shell lab: –Job data structures –Shared between main process and signal handler Need ways to synchronize multiple control of flows

17 15213 RecitationAnubhav Gupta17 Threads 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

18 15213 RecitationAnubhav Gupta18 Caveats of Conceptual Models All global variables are shared. All static local variables are shared. In practice, any thread can read and write the stack of any other thread. So one can use a global pointer to point to a stack variable. Then all threads can access the stack variable. But this is not a good programming practice. More about this in this Thu’s lecture

19 15213 RecitationAnubhav Gupta19 Sharing With POSIX Semaphores #include "csapp.h" #define NITERS 10000000 unsigned int cnt; /* counter */ sem_t sem; /* semaphore */ int main() { pthread_t tid1, tid2; /* create 2 threads and wait */...... exit(0); } /* thread routine */ void *count(void *arg) { int i; for (i=0;i<NITERS;i++){ cnt++; } return NULL; }

20 15213 RecitationAnubhav Gupta20 Synchronization If multiple threads want to access a shared global data structure, we need to synchronize their accesses. Ways to do synchronization: –Semaphores –Mutex and conditions –Etc.

21 15213 RecitationAnubhav Gupta21 Synchronizing With Semaphores Classic solution: Dijkstra's P and V operations on semaphores. –semaphore: non-negative integer synchronization variable. P(s): [ while (s == 0) wait(); s--; ] –Dutch for "Proberen" (test) V(s): [ s++; ] –Dutch for "Verhogen" (increment) –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)

22 15213 RecitationAnubhav Gupta22 POSIX Semaphores (in csapp.c) /* initialize semaphore sem to value */ /* pshared=0 if thread, pshared=1 if process */ void Sem_init(sem_t *sem, int pshared, unsigned int value) { if (sem_init(sem, pshared, value) < 0) unix_error("Sem_init"); } /* P operation on semaphore sem */ void P(sem_t *sem) { if (sem_wait(sem)) unix_error("P"); } /* V operation on semaphore sem */ void V(sem_t *sem) { if (sem_post(sem)) unix_error("V"); }

23 15213 RecitationAnubhav Gupta23 Sharing With POSIX Semaphores #include "csapp.h" #define NITERS 10000000 unsigned int cnt; /* counter */ sem_t sem; /* semaphore */ int main() { pthread_t tid1, tid2; Sem_init(&sem, 0, 1); /* create 2 threads and wait */...... exit(0); } /* thread routine */ void *count(void *arg) { int i; for (i=0;i<NITERS;i++){ P(&sem); cnt++; V(&sem); } return NULL; }

24 15213 RecitationAnubhav Gupta24 Signaling With Semaphores Common synchronization pattern: –Producer waits for slot, inserts item in buffer, and “signals” consumer. –Consumer waits for item, removes it from buffer, and “signals” producer. “signals” in this context has nothing to do with Unix signals producer thread shared buffer consumer thread

25 15213 RecitationAnubhav Gupta25 Producer-Consumer (1-Buffer) /* buf1.c - producer- consumer on 1-element buffer */ #include “csapp.h” #define NITERS 5 void *producer(void *arg); void *consumer(void *arg); struct { int buf; /*shared var */ sem_t full; /* sems */ sem_t empty; } shared; int main() { pthread_t tid_producer; pthread_t tid_consumer; /* initialize the semaphores */ Sem_init(&shared.empty, 0, 1); Sem_init(&shared.full, 0, 0); /* create threads and wait */ Pthread_create(&tid_producer, NULL, producer, NULL); Pthread_create(&tid_consumer, NULL, consumer, NULL); Pthread_join(tid_producer, NULL); Pthread_join(tid_consumer, NULL); exit(0); }

26 15213 RecitationAnubhav Gupta26 Producer-Consumer (cont) /* producer thread */ void *producer(void *arg) { int i, item; for (i=0; i<NITERS; i++) { /* produce item */ item = i; printf("produced %d\n", item); /* write item to buf */ P(&shared.empty); shared.buf = item; V(&shared.full); } return NULL; } /* consumer thread */ void *consumer(void *arg) { int i, item; for (i=0; i<NITERS; i++) { /* read item from buf */ P(&shared.full); item = shared.buf; V(&shared.empty); /* consume item */ printf("consumed %d\n", item); } return NULL; } Initially: empty = 1, full = 0.

27 15213 RecitationAnubhav Gupta27 Thread-safety of 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 functionClassReentrant version asctime 3asctime_r ctime 3ctime_r gethostbyaddr 3gethostbyaddr_r gethostbyname 3gethostbyname_r inet_ntoa 3(none) localtime 3localtime_r rand 2rand_r

28 15213 RecitationAnubhav Gupta28 Thread-Unsafe Functions: Fixes Return a ptr to a static variable. Fixes: 1. Rewrite code so caller passes pointer to struct. Issue: Requires changes in caller and callee. hostp = Malloc(...)); gethostbyname_r(name, hostp); struct hostent *gethostbyname(char name) { static struct hostent h; return &h; }

29 15213 RecitationAnubhav Gupta29 Thread-Unsafe Functions: Fixes Return a ptr to a static variable. Fixes: 2. Lock-and-copy Issue: Requires only simple changes in caller However, caller must free memory. struct hostent *gethostbyname(char name) { static struct hostent 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; }

30 15213 RecitationAnubhav Gupta30 Summary Threading is a clean and efficient way to implement concurrent server We need to synchronize multiple threads for concurrent accesses to shared variables –Semaphore is one way to do this –Thread-safety is the difficult part of thread programming


Download ppt "Concurrency Threads Synchronization Thread-safety of Library Functions Anubhav Gupta Dec. 2, 2002 Outline."

Similar presentations


Ads by Google