Threads
• Lightweight processes
• What’s wrong with processes?– fork() is expensive – 10 to 100 times slower– Inter process communication
• For returning information from child to parent
Threads…• Shared components
– Global memory– Instructions– Most data– Open descriptors (files, sockets etc)– Signal handlers
• Not shared…– Thread ID– Registers, Program counter, stack pointer– Stack– Errno– Signal mask– Priority
Creation
• Thread equivalent of fork()
• int pthread_create(pthread_t * thread,
pthread_attr_t * attr,
void * (*start_routine)(void *),
void * arg
);
• Returns 0 is OK, and non-zero (> 0) if error.
Termination
• Return from initial fuction.• void pthread_exit(void * status)• exit() called by any thread• main() returns
Waiting for child thread to exit
• int pthread_join(pthread_t tid, void **status)
• Equivalent of waitpid()
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())
Echo client-server
Server
S1 S2
ReadThread
WriteThread
ReadThread
WriteThread
listenfd
Read Write WriteReadClient1 Client2
main()
{int listenfd, connfd;
int len;
/* 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(NULL, NULL, service_func, (void *) connfd);
}
}
void * service_func(void *arg){
int local_connfd;
/* release parent from waiting */Pthread_detach(pthread_self());
/* extract connfd from argument */local_connfd = (int) arg;
/* receive and echo client’s message */str_echo(local_connfd);
/* Terminate the connection */Close(local_connfd);
return(NULL);
}
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);
}
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;
}
Mutex – for mutual exclusion
int counter = 0;
void *thread_func(void *arg){int val;
/* unprotected code – why? */val = counter;counter = val + 1;
return NULL;}
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;}
Condition Variable – for signaling
• Think of Producer – consumer problem
• Producers and consumers run in separate threads.
• Producer produces data and consumer consumes data.
• Consumer has to inform producer when data is available
/* Globals */
int data_avail = 0;
int pthread_mutex_t data_mutex =PTHREAD_MUTEX_INITIALIZER;
void *producer(void *)
{
Pthread_mutex_lock(&data_mutex);
Produce data
Insert data into queue;
data_avail++;
Pthread_mutex_unlock(&data_mutex);
consume_data();
}
void *consumer(void *)
{
Pthread_mutex_lock(&data_mutex);
while( !data_avail )
/* do nothing – keep looping!!*/;
Extract data from queue;
if (queue is empty) data_avail = 0;
Pthread_mutex_unlock(&data_mutex);
consume_data();
}
int data_avail = 0;int pthread_mutex_t data_mutex =PTHREAD_MUTEX_INITIALIZER;int pthread_cont_t data_cond = PTHREAD_COND_INITIALIZER;
void *producer(void *) {
Pthread_mutex_lock(&data_mutex);
Produce data
Insert data into queue;data_avail++;
Pthread_cond_signal(&data_cond);
Pthread_mutex_unlock(&data_mutex);
consume_data();}
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();}
ioctl()
• Handles miscellaneous properties of a file/device referenced by a descriptor.– In our case, network interfaces.
• int ioctl(int fd, int request, void * arg)
– Socket operations– File operations– Interface configuration– ARP cache– Routing table
• SIOSPGRP/SIOGPGRP– set/get process/group ID of a socket
• FIONREAD– Return number of bytes in socket buffer
• SIOCGIFCONF– Get list of all interfaces
• SIOCGIFBRDADDR/ SIOCSIFBRDADDR– Get/set broadcast address
• SIOCGARP/SIOCSARP/SIOCDARP– Get/modify/delete ARP cache entry.
• SIOCADDRT/SIOCDELRT– Add/delete routes