Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
24 views

CS307 Lecture 1

The document discusses concurrency and threads. It defines threads as the smallest unit of execution in an operating system that runs within a program and shares code, data, and resources with other threads. The document describes the different states a thread can be in, such as new, runnable, running, non-running/waiting, and dead. It also discusses the two main types of threads - user level threads managed by user applications and kernel level threads managed by the operating system kernel. Finally, it covers key thread concepts like thread control blocks, differences between processes and threads, and advantages/disadvantages of multithreading.

Uploaded by

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

CS307 Lecture 1

The document discusses concurrency and threads. It defines threads as the smallest unit of execution in an operating system that runs within a program and shares code, data, and resources with other threads. The document describes the different states a thread can be in, such as new, runnable, running, non-running/waiting, and dead. It also discusses the two main types of threads - user level threads managed by user applications and kernel level threads managed by the operating system kernel. Finally, it covers key thread concepts like thread control blocks, differences between processes and threads, and advantages/disadvantages of multithreading.

Uploaded by

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

Concurrency and Threads

CS307: Systems Practicum


Prof. Varun Dutt, IIT Mandi
Threads
● In general, as we know that thread is a very thin twisted string usually of the cotton or
silk fabric and used for sewing clothes and such. The same term thread is also used in
the world of computer programming.

● In clothes, thread hold the cloth together and on the other side, in computer
programming, thread hold the computer program and allow the program to execute
sequential actions or many actions at once.

● Thread is the smallest unit of execution in an operating system. It is not in itself a


program but runs within a program. In other words, threads are not independent of one
other and share code section, data section, etc. with other threads. These threads are
also known as lightweight processes.
States of a Thread
Typically, a thread can exist in five distinct states. The different states are shown
below:
● New Thread: A new thread begins its life cycle in the new state.
However, at this stage, it has not yet started and it has not been
allocated any resources. We can say that it is just an instance of an
object.
● Runnable: As the newly born thread is started, the thread becomes
runnable i.e. waiting to run. In this state, it has all the resources but still
task scheduler have not scheduled it to run.
● Running: In this state, the thread makes progress and executes the task,
which has been chosen by task scheduler to run. Now, the thread can go
to either the dead state or the non-runnable/ waiting state.
● Non-running/waiting: In this state, the thread is paused because it is
either waiting for the response of some I/O request or waiting for the
completion of the execution of other thread.
● Dead: A runnable thread enters the terminated state when it completes
its task or otherwise terminates.
Types of Thread
1. User Level Thread
These are user-managed threads.

In this case, the thread management kernel is not


aware of the existence of threads. The thread
library contains code for creating and destroying
threads, for passing message and data between
threads, for scheduling thread execution and for
saving and restoring thread contexts. The
application starts with a single thread.

The examples of user level threads are − Java


threads. POSIX threads
User level threads
Advantages:

● Thread switching does not require Kernel mode privileges.


● User level thread can run on any operating system.
● Scheduling can be application specific in the user level thread.
● User level threads are fast to create and manage.

Disadvantages:

● In a typical operating system, most system calls are blocking.


● Multithreaded application cannot take advantage of multiprocessing.


2. Kernel Level Threads
● Operating System managed threads act on kernel, which is an
operating system core.
● In this case, the Kernel does thread management. There is no
thread management code in the application area. Kernel threads
are supported directly by the operating system. Any application
can be programmed to be multithreaded. All of the threads
within an application are supported within a single process.
● The Kernel maintains context information for the process as a
whole and for individual threads within the process. Scheduling
by the Kernel is done on a thread basis. The Kernel performs
thread creation, scheduling and management in Kernel space.
Kernel threads are generally slower to create and manage than
the user threads.
Kernel Level Threads
The examples of kernel level threads are Windows, Solaris.

Advantages:
● Kernel can simultaneously schedule multiple threads from the same process on
multiple processes.
● If one thread in a process is blocked, the Kernel can schedule another thread of the same process.
● Kernel routines themselves can be multithreaded.

Disadvantages:
● Kernel threads are generally slower to create and manage than the user threads.
● Transfer of control from one thread to another within the same process requires a mode switch to
the Kernel.
Thread Control Block (TCB)
Thread Control Block (TCB) may be defined as the data structure in
the kernel of operating system that mainly contains information about
thread. Thread-specific information stored in TCB would highlight
some important information about each process..
Consider the following points related to the threads contained in TCB:

● Thread identification − It is the unique thread id (tid) assigned to every new thread.
● Thread state − It contains the information related to the state (Running, Runnable, Non-Running, Dead) of the thread.
● Program Counter (PC) − It points to the current program instruction of the thread.
● Register set − It contains the thread’s register values assigned to them for computations.
● Stack Pointer − It points to the thread’s stack in the process. It contains the local variables under thread’s scope.
● Pointer to PCB − It contains the pointer to the process that created that thread
Process vs Thread
● In multithreading, process and thread are two very closely related terms having the same goal to make
computer able to do more than one thing at a time. A process can contain one or more threads but on the
contrary, thread cannot contain a process. However, they both remain the two basic units of execution. A
program, executing a series of instructions, initiates process and thread both.

Process Thread

1. Process is heavy weight or resource intensive. 1. Thread is lightweight which takes fewer resources than a
2. Process switching needs interaction with operating system. process.
3. In multiple processing environments, each process executes 2. Thread switching does not need to interact with operating
the same code but has its own memory and file resources. system.
4. If one process is blocked, then no other process can execute 3. All threads can share same set of open files, child processes.
until the first process is unblocked. 4. While one thread is blocked and waiting, a second thread in
5. Multiple processes without using threads use more the same task can run.
resources. 5. Multiple threaded processes use fewer resources.
6. In multiple processes, each process operates 6. One thread can read, write or change another thread's
independently of the others. data.
7. If there would be any change in the parent process then it 7. If there would be any change in the main thread then it
does not affect the child processes. may affect the behavior of other threads of that process.
8. To communicate with sibling processes, processes must 8. Threads can directly communicate with other threads of
use inter-process communication. that process.
Multithreading
The following diagram helps us understand how multiple
threads exist in memory −

● Multithreading is the ability of a CPU to manage


the use of operating system by executing multiple
threads concurrently.
● The main idea of multithreading is to achieve
parallelism by dividing a process into multiple
threads. In a more simple way, we can say that
multithreading is the way of achieving
multitasking by using the concept of threads.
● Example: Suppose we are running a process. The
process could be for opening MS word for writing
something. In such process, one thread will be
assigned to open MS word and another thread
will be required to write. Now, suppose if we
want to edit something then another thread will We can see in the above diagram that more than one thread can
exist within one process where every thread contains its own
be required to do the editing task and so on.
register set and local variables. Other than that, all the threads in
a process share global variables.
Pros & Cons of Multithreading
Advantages:
● Speed of communication − Multithreading improves the speed of computation because each core or
processor handles separate threads concurrently.
● Program remains responsive − It allows a program to remain responsive because one thread waits for
the input and another runs a GUI at the same time.
● Access to global variables − In multithreading, all the threads of a particular process can access the
global variables and if there is any change in global variable then it is visible to other threads too.
● Utilization of resources − Running of several threads in each program makes better use of CPU and the
idle time of CPU becomes less.
● Sharing of data − There is no requirement of extra space for each thread because threads within a
program can share same data.
Pros & Cons of Multithreading
Disadvantages:
● Not suitable for single processor system − Multithreading finds it difficult to achieve performance in
terms of speed of computation on single processor system as compared with the performance on
multi-processor system.
● Issue of security − As we know that all the threads within a program share same data, hence there is
always an issue of security because any unknown thread can change the data.
● Increase in complexity − Multithreading can increase the complexity of the program and debugging
becomes difficult.
● Lead to deadlock state − Multithreading can lead the program to potential risk of attaining the
deadlock state.
● Synchronization required − Synchronization is required to avoid mutual exclusion. This leads to more
memory and CPU utilization.
Implementation of threads using Python
● Threads are lightweight processes and occupies much lesser memory than processes
● Threads perform multiple tasks at the same time
● In Python, there are two modules that implements threads in the program:

1. <_thread> module : treats a thread as a function

2. <threading> module : treats every thread as an object and implements it in an object oriented way

● <_thread>module is effective in low level threading and has fewer capabilities than the <threading>
module.
<threading> module
● The <threading> module implements in an object oriented way and treats every thread as an object. Therefore,
it provides much more powerful, high-level support for threads than the <_thread> module. This module is
included with Python 2.4.

● Additional methods of <threading> module: The <threading> module comprises all the methods of the
<_thread> module but it provides additional methods as well. The additional methods are as follows −
● threading.activeCount() − This method returns the number of thread objects that are active
● threading.currentThread() − This method returns the number of thread objects in the caller's thread
control.
● threading.enumerate() − This method returns a list of all thread objects that are currently active.
● For implementing threading, the <threading> module has the Thread class which
provides the following methods −
● run() − The run() method is the entry point for a thread
● start() − The start() method starts a thread by calling the run method.
● join([time]) − The join() waits for threads to terminate.
● isAlive() − The isAlive() method checks whether a thread is still executing.
● getName() − The getName() method returns the name of a thread.
● setName() − The setName() method sets the name of a thread.
How to create threads using <threading>
module?
Follow these steps to create a new thread using the <threading> module −

● Step 1 − In this step, we need to define a new subclass of the Thread class.
● Step 2 − Then for adding additional arguments, we need to override the __init__(self [,args]) method.
● Step 3 − In this step, we need to override the run(self [,args]) method to implement what the thread
should do when started.

Now, after creating the new Thread subclass, we can create an instance of it and then start a new thread by
invoking the start(), which in turn calls the run() method.
Example
Consider this example to learn how to generate
a new thread by using the <threading> module.
Output
Now, consider the following output −
Python program for various thread states
There are five thread states - new, runnable, running,
waiting and dead. Among these five Of these five, we
will majorly focus on three states - running, waiting
and dead. A thread gets its resources in the running
state, waits for the resources in the waiting state; the
final release of the resource, if executing and
acquired is in the dead state.

The following Python program with the help of


start(), sleep() and join() methods will show how a
thread entered in running, waiting and dead state
respectively.
Starting a thread in python
In python, we can start a new thread by
different ways but the easiest one among them
is to define it as a single function. After defining
the function, we can pass this as the target for a
new threading.Thread object and so on. Execute
the following Python code to understand how
the function works −
Output
Daemon threads
● Daemon is a background process that handles the requests for various services such as data
sending, file transfers, etc.
● The same task can be done with the help of non-daemon threads also. However, in this case, the
main thread has to keep track of the non-daemon threads manually.
● On the other hand, if we are using daemon threads then the main thread can completely forget
about this and it will be killed when main thread exits.
● Daemon threads can only be used for non-essential tasks that would not affect us if it does not
complete or gets killed in between
Implementation of daemon threads in python

In the above code, there are two functions namely


>nondaemonThread() and >daemonThread().
The first function prints its state and sleeps after
8 seconds while the the deamonThread() function
prints Hello after every 2 seconds indefinitely.
Output
We can understand the difference between
non-daemon and daemon threads with the
help of following output
Synchronizing Threads
● Thread synchronization may be defined as a method with the help of which we can be assured that
two or more concurrent threads are not simultaneously accessing the program segment known as
critical section.
● Synchronization is the process of making sure that two or more threads do not interface with each
other by accessing the resources at the same time.
● The diagram below shows that four threads trying to access the critical section of a program at the
same time.
Issues in thread synchronization

The two Major issue are:-

● Race Condition:- A race condition may be defined as the occurring of a condition when two or more
threads can access shared data and then try to change its value at the same time. Due to this, the
values of variables may be unpredictable and vary depending on the timings of context switches of
the processes.
Example-Race Condition
Consider this example to understand the concept of race condition −
Dealing with race condition using locks
● In Python, the <threading>module provides Lock class to deal with race condition. Further, the Lock class provides
different methods with the help of which we can handle race condition between multiple threads. The methods are
described below −
1. acquire() method
This method is used to acquire, i.e., blocking a lock. A lock can be blocking or non-blocking depending upon the following true
or false value −

● With value set to True − If the acquire() method is invoked with True, which is the default argument, then the
thread execution is blocked until the lock is unlocked.
● With value set to False − If the acquire() method is invoked with False, which is not the default argument, then
the thread execution is not blocked until it is set to true, i.e., until it is locked.
2. release() method
This method is used to release a lock. Following are a few important tasks related to this method −

● If a lock is locked, then the release() method would unlock it. Its job is to allow exactly one thread to proceed if more
than one threads are blocked and waiting for the lock to become unlocked.
● It will raise a ThreadError if lock is already unlocked.
Python program to understand the concept of locks for dealing
with race condition −
Deadlocks − The Dining Philosophers problem
● Deadlock is a troublesome issue one can face while designing the concurrent systems. We can
illustrate this issue with the help of the dining philosopher problem as follows:-
● In this problem, there are five famous philosophers sitting at a round table eating some food from
their bowls. There are five forks that can be used by the five philosophers to eat their food. However,
the philosophers decide to use two forks at the same time to eat their food.
● Now, there are two main conditions for the philosophers. First, each of the philosophers can be either
in eating or in thinking state and second, they must first obtain both the forks, i.e., left and right.
● The issue arises when each of the five philosophers manages to pick the left fork at the same time.
Now they all are waiting for the right fork to be free but they will never relinquish their fork until
they have eaten their food and the right fork would never be available. Hence, there would be a
deadlock state at the dinner table
Solution- The Dining Philosophers problem

● The solution of this problem can be found by splitting the philosophers into two types – greedy
philosophers and generous philosophers.

● Mainly a greedy philosopher will try to pick up the left fork and wait until it is there. He will then
wait for the right fork to be there, pick it up, eat and then put it down.

● On the other hand, a generous philosopher will try to pick up the left fork and if it is not there, he will
wait and try again after some time. If they get the left fork then they will try to get the right one. If
they will get the right fork too then they will eat and release both the forks.
Solution with Python program
The Below program uses the concept of greedy and generous philosophers. The program has also used the acquire()
and release() methods of the Lock class of the <threading> module
References

● https://www.tutorialspoint.com/concurrency_in_python/concurrency_in_python_threads.htm

You might also like