CS303-Lab 5 (2)
CS303-Lab 5 (2)
Lab: Threading
1. Overview
a) What are threads?
• Threads have some advantages over processes. Compared to the standard fork(), threads
carry a lot less overhead.
• Remember: fork() produces a second copy of the calling process. The parent and the child
are completely independent, each with its own address space, with its own copies of its
variables, which are completely independent of the same variables in the other process.
• Threads share a common address space, thereby avoiding a lot of the inefficiencies of
multiple processes.
• The kernel does not need to make a new independent copy of the process memory space, file
descriptors, etc. This saves a lot of CPU time, making thread creation ten to a hundred times
faster than a new process creation.
• Less time to terminate a thread than a process.
• Context switching between threads is much faster then context switching between processes
(context switching means that the system switches from running one thread or process, to
running another thread or process)
• Less communication overheads -- communicating between the threads of one process is
simple because the threads share the address space. Data produced by one thread is
immediately available to all the other threads.
• Because threads in a group all use the same memory space, if one of them corrupts the
contents of its memory, other threads might suffer as well.
• With processes, the operating system normally protects processes from one another, and thus
if one corrupts its own memory space, other processes won't suffer.
• The maximum number of threads permitted, and the default thread stack size are two
important limits to consider when designing your program. Programs that attempt to exceed
the limit of threads to be created can fail or produce wrong results.
• When a multi-threaded program starts executing, it has one thread running, which
executes the main() function of the program. This is already a fully-established thread,
with its own thread ID.
Syntax Description
#include <pthread.h> pthread functions and data structures
pthread_t thread_id; declare a variable called thread_id, which is
of type pthread_t. This is basically an integer
used to identify the thread in the system.
pthread_create (thread,attr,start_routine,arg) - Call the pthread_create function to create a
real, living thread.
- The 1st argument is a pointer to thread_id to
supply the program with the thread's
identifier.
- The 2nd argument is used to set some
attributes for the new thread. NULL for the
default values.
- The 3rd argument is the C routine that the
thread will execute once it is created.
- The 4th argument is the argument that may
be passed to the C function. NULL may be
used if no argument is to be passed.
- pthread_create() returns zero on success and
a non-zero value on failure
pthread_exit(void *return_value); The call to pthread_exit causes the current
thread to exit and free any thread-specific
resources it is taking.
pthread_self(); A thread can get its own thread id by
calling pthread_self(), which returns the
thread id:
pthread_join(thread_id, NULL); - A join is performed when one wants to wait
for a thread to finish. A thread calling routine
may launch multiple threads then wait for
them to finish to get the results.
- join for threads is the equivalent of wait for
processes.
- pthread_join blocks the calling thread until
thread: thread_id terminates (returns NULL).
2. Exercise 1
Write lab_prog.c that implements this thread tree :
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
void *threadA ( void * arg) { void *threadB ( void * arg){ void *threadC ( void * arg) {
printletter(10 , 'A') ; // thread A pthread_t thC ; // declare new printletter(5 , 'C') ; // thread C
will display the letter A, 10 times variable with the id of thread C will display the letter C, 5 times
printf ( "\nThread A is finished pthread_create(&thC , NULL, printf ( "\nThread C is finished
\n" ) ; threadC , NULL) ; // create the \n" ) ;
pthread_exit (NULL) ; thread C that will execute the pthread_exit (NULL) ;
} routine threadC }
printletter(10 , 'B') ;
printf ( "\nThread B is waiting
for thread C to terminate \n" ) ;
pthread_join ( thC ,NULL) ; //
thread B is waiting for the
termination of thread C
printf("\nThread B is finished
\n") ;
pthread_exit (NULL) ;
}
int main() {
pthread_t thA , thB ; //declaring the variables id for both threads A and B
printf ( "Main thread is creating the threads A and B : \n" ) ;
pthread_create (&thA , NULL, threadA , NULL) ; //creating the thread A with the id: thA. Thread A is
executing the routine threadA
printf ( "Main thread is waiting for the termination of the thread A : \n") ;
pthread_join (thA ,NULL) ; //main thread is waiting for thread A to terminate
pthread_create (&thB , NULL, threadB , NULL) ; //creating the thread B with the id: thB. Thread B is
executing the routine threadB
printf ( "Main thread is waiting for the termination of the thread B : \n") ;
pthread_join ( thB ,NULL) ; //main thread is waiting for thread B to terminate
printf ( "\nMain thread is finished \n" ) ;
return 0;
}
Compile lab_prog.c:
In order to compile a multi-threaded program using gcc, you need to link it with the pthreads library.
Assuming you have this library already installed on your system, here is how to compile your first program:
NB: If the pthreads library is not installed, please install it using the commands below:
./lab_prog
a) Write a program hellomany.c that will create 3 threads, each of which prints out a hello message
and its own thread ID and process ID.
NB:
• To get the number of threads from the arguments’ list in the console, use: int nbre = atoi(argv[1]);
• To set a pointer to the table of threads, use: pthread_t * th;
• To create the table of your threads, use: th = malloc(n * sizeof(pthread_t));
• Your main should support the list of arguments: int main(int agrc, char** argv) {…}
• Use the “for” loop to create your nbre of threads.
• Add your headers:
o #include <stdio.h>
o #include <unistd.h>
o #include <stdlib.h>
o #include <sys/types.h>
o #include <pthread.h>