1 / 27

Threads

Threads. Chapter 26. Threads. Light-weight processes Each process can have multiple threads of concurrent control. What’s wrong with processes? fork() is expensive 10 to 100 times slower Copy of everything in parent. Inter process communication

molimo
Download Presentation

Threads

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Threads Chapter 26

  2. Threads • Light-weight processes • Each process can have multiple threads of concurrent control. • What’s wrong with processes? • fork() is expensive • 10 to 100 times slower • Copy of everything in parent. • Inter process communication • For returning information from child to parent

  3. Threads… • Shared components • Global memory • Instructions • Most data • Open descriptors (files, sockets etc) • Signal handlers • Not shared • Registers, Program counter, stack pointer • Thread ID • Stack • Errno • Priority

  4. Advantages of Threads • Light-weight • Lower Context Switching Overhead • Fewer OS resources • Shared State • Don’t need IPC-like mechanism to communicate between threads of same process

  5. Disadvantages of Threads • Shared State! • Global variables are shared between threads. Accidental changes can be fatal. • Many library functions are not thread-safe • Library Functions that return pointers to static internal memory. E.g. gethostbyname() • Lack of robustness • Crash in one thread will crash the entire process.

  6. Creation • Thread equivalent of fork() • int pthread_create( pthread_t * thread, pthread_attr_t * attr, void * (*start_routine)(void *), void * arg ); • Returns 0 if OK, and non-zero (> 0) if error.

  7. Termination Thread Termination • Return from initial function. • void pthread_exit(void * status) Process Termination • exit()called by any thread • main() returns

  8. Waiting for child thread • int pthread_join( pthread_t tid, void **status) • Equivalent of waitpid()for processes

  9. Detaching a thread • The detached thread can act as daemon thread • The parent thread doesn’t need to wait • int pthread_detach(pthread_t tid) • Detaching self : pthread_detach(pthread_self())

  10. Echo client-server Server listenfd S1 S2 Read Read Write Write Client2 Client1 Read Thread Write Thread Read Thread Write Thread

  11. Thread-based Echo Server

  12. main() { int listenfd, connfd; int len; pthread_t tid; /* Start the usual way */ listenfd = Socket(…); Bind(listenfd, …); Listen(listenfd, …) for ( ; ; ) { len = addrlen; connfd = Accept(listenfd, …); /* Create a thread in service_func routine */ Pthread_create(&tid, NULL, service_func, ???? ); } } How to pass connfd? (void *) arg

  13. main() { int listenfd, connfd; int len; pthread_t tid; /* Start the usual way */ listenfd = Socket(…); Bind(listenfd, …); Listen(listenfd, …) for ( ; ; ) { len = addrlen; cptr = Malloc(sizeof(int)); *cptr = Accept(listenfd, …); /* Create a thread in service_func routine */ Pthread_create(&tid, NULL, service_func, (void *) cptr); } }

  14. void * service_func(void *arg) { int local_connfd; /* release parent from waiting */ Pthread_detach(pthread_self()); /* extract connfd from argument */ local_connfd = *((int *) arg); free(arg); /* receive and echo client’s message See Figure 5.3, page 124, Steven’s book*/ str_echo(local_connfd); /* Terminate the connection */ Close(local_connfd); return(NULL); }

  15. Thread-based Echo Client Why is single threaded client not good enough? Multi-threaded Client 

  16. int sockfd; FILE *fp; main() { pthread_t tid; fp = fopen(…); /* Start the usual way */ sockfd = Socket(…); … Connect(…); /* Create a thread to send data */ Pthread_create(&tid, NULL, write_func, NULL); /* read data from sockfd */ read_func(); /* wait for child thread */ Pthread_join(tid, NULL); }

  17. void * write_func(void *arg) { char sendline[MAXLINE]; while( more data in fp) Read from fp into sendline[]; Write sendline[] into sockfd; Shutdown(sockfd, SHUT_WR); return(NULL); } void read_func() { char recvline[MAXLINE]; while ( more data from sockfd) Read from sockfd into recvline[]; Write from recvline[] to stdout; }

  18. Locking in Threads

  19. Mutex – for mutual exclusion int counter = 0; void *thread_func(void *arg) { int val; /* unprotected code – why? */ val = counter; counter = val + 1; return NULL; }

  20. Mutex… int counter = 0; ptread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; void *thread_func(void *arg) { int val; /* protected by mutex */ Pthread_mutex_lock( &mutex ); val = counter; counter = val + 1; Pthread_mutex_unlock( &mutex ); return NULL; }

  21. Condition Variable – for signaling • Think of Producer – consumer problem • Producers and consumers run in separate threads. • Producer produces data and consumer consumes data. • Producer has to inform the consumer when data is available • Consumer has to inform producer when buffer space is available

  22. Without Condition Variables

  23. /* Globals */ int data_avail = 0; pthread_mutex_t data_mutex = PTHREAD_MUTEX_INITIALIZER; void *producer(void *) { Pthread_mutex_lock(&data_mutex); Produce data Insert data into queue; data_avail=1; Pthread_mutex_unlock(&data_mutex); }

  24. void *consumer(void *) { while( !data_avail ); /* do nothing – keep looping!!*/ Pthread_mutex_lock(&data_mutex); Extract data from queue; if (queue is empty) data_avail = 0; Pthread_mutex_unlock(&data_mutex); consume_data(); }

  25. With Condition Variables

  26. int data_avail = 0; pthread_mutex_t data_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cont_t data_cond = PTHREAD_COND_INITIALIZER; void *producer(void *) { Pthread_mutex_lock(&data_mutex); Produce data Insert data into queue; data_avail = 1; Pthread_cond_signal(&data_cond); Pthread_mutex_unlock(&data_mutex); }

  27. void *consumer(void *) { Pthread_mutex_lock(&data_mutex); while( !data_avail ) { /* sleep on condition variable*/ Pthread_cond_wait(&data_cond, &data_mutex); } /* woken up */ Extract data from queue; if (queue is empty) data_avail = 0; Pthread_mutex_unlock(&data_mutex); consume_data(); }

More Related