0% found this document useful (0 votes)
8 views

CS303-Lab 5 (2)

The document provides an overview of threading in operating systems, explaining what threads are, their advantages and limitations, and the concept of POSIX threads (pthreads). It details the creation, termination, and scheduling of threads, along with example code for implementing multi-threaded programs in C. Additionally, it includes exercises for creating and managing threads, emphasizing the importance of synchronization and resource sharing among threads.

Uploaded by

anischelly95
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
8 views

CS303-Lab 5 (2)

The document provides an overview of threading in operating systems, explaining what threads are, their advantages and limitations, and the concept of POSIX threads (pthreads). It details the creation, termination, and scheduling of threads, along with example code for implementing multi-threaded programs in C. Additionally, it includes exercises for creating and managing threads, emphasizing the importance of synchronization and resource sharing among threads.

Uploaded by

anischelly95
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 8

CS303 Operating Systems

Lab: Threading

1. Overview
a) What are threads?

• A thread is an independent stream of instructions that can be scheduled to run by the


operating system.
• A thread is a semi-process that has its own stack, and executes a given piece of code.
• Unlike a real process, the thread normally shares its memory with other threads (whereas
for processes we usually have a different memory area for each one of them).
• A Thread Group is a set of threads all executing inside the same process. They all share the
same memory, and thus can access the same global variables, same heap memory, same set
of file descriptors, etc. All these threads execute in parallel.

Figure 1:,Single- and Multi-Threaded Processes

In summary, in the UNIX environment a thread:


• Exists within a process and uses the process resources.
• Has its own independent flow of control as long as its parent process exists and the OS
supports it.
• Duplicates only the essential resources it needs to be independently schedulable.
• May share the process resources with other threads that act equally independently (and
dependently).
• Dies if the parent process dies.
• Is “lightweight” because most of the overhead has already been accomplished through the
creation of its process.
Because threads within the same process share resources:
• Changes made by one thread to shared system resources (such as closing a file) will be seen
by all other threads.
• Two pointers having the same value point to the same data.
• Reading and writing to the same memory locations is possible, and therefore requires
explicit synchronization by the programmer.

b) What are pthreads ?

• In order to take full advantage of the capabilities provided by threads, a standardized


programming interface was required. For UNIX systems, this interface has been specified
by the IEEE POSIX 1003.1c standard (1995). Implementations which adhere to this
standard are referred to as POSIX threads, or Pthreads.
• Pthreads are defined as a set of C language programming types and procedure calls,
implemented with a pthread.h header/include file and a thread library - though this library
may be part of another library, such as libc, in some implementations.

c) What are the advantages of 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.

d) What are the limitations of 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.

e) Threads’ basics (creation – termination – scheduling):

• 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>

// this routine will be called by the three threads A, B, and C


void *printletter( int n , char letter) {
int i ;
for ( i = 0 ; i < n; i ++){
printf ("%c " , letter) ;
}
}

Please insert the three routines of the three threads HERE!

Thread A Thread B Thread C


//this routine will be executed by //this routine will be executed by //this routine will be executed by
thread A thread B thread C

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:

gcc lab_prog.c -o lab_prog -lpthread

NB: If the pthreads library is not installed, please install it using the commands below:

sudo apt update


apt-get install libpthread-stubs0-dev

Run the program lab_prog:

./lab_prog

This is the output of our program:


3. Exercise 2

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.

This is the output of your program:


b) Now update the same program in a way to create a number N of threads specified in the
command line, 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>

This is the expected output:

You might also like