0% found this document useful (0 votes)
7 views64 pages

OS Lab - 1 HANDOUT

Uploaded by

hoomanparsaei9
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views64 pages

OS Lab - 1 HANDOUT

Uploaded by

hoomanparsaei9
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 64

OS-Lab 1

Mehrdad Ahmadzadeh

Mehrdad Ahmadzadeh OS-Lab 1


Python

Processes and Threads


A process is an executing instance of an application
For example, double-clicking on the Internet browser icon on
the desktop will start a process that runs the browser.
A thread is an active flow of control that can be activated in
parallel with other threads within the same process.
A thread is sometimes called a lightweight process because it
shares many characteristics of a process.

Mehrdad Ahmadzadeh OS-Lab 1


Python

Is Prime?

Mehrdad Ahmadzadeh OS-Lab 1


Python

Is Prime?

Mehrdad Ahmadzadeh OS-Lab 1


Python

Is Prime?

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism

Global Interpreter Lock (GIL)


The Python interpreter is not fully thread-safe
It is possible that multiple threads would execute at once
causing unpredictable outputs
In CPython, the global interpreter lock, or GIL, is a mutex
that protects access to Python objects, preventing multiple
threads from executing Python bytecodes at once.
A global interpreter lock (GIL) is a mutual-exclusion lock held
by a programming language interpreter thread to avoid
sharing code that is not thread-safe with other threads

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism

02-example2.py
While there was no actual concurrency involved in the second
method, the overhead cost of spawning new threads
contributed to the significantly worse execution time.
This is one example of inherently sequential tasks, where
concurrency or parallelism should not be applied to attempt
an improvement in execution time.

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism

Global Interpreter Lock (GIL)


Python automatically switches to the next thread after a short
period of time or when a thread does something that may
take a while.
The GIL is not enough to avoid problems in your own
programs.
Although, if multiple threads attempt to access the same data
object, it may end up in an inconsistent state.

Mehrdad Ahmadzadeh OS-Lab 1


Python

Concurrency in Python
Concurrency in Python can be achieved through several
mechanisms, each with its own characteristics and use cases.
Multithreading
Multiprocessing
Asyncio
Concurrent Futures

Mehrdad Ahmadzadeh OS-Lab 1


Python

Multithreading
Python provides the threading module, which allows you to
run multiple threads (smaller units of a process) concurrently.
However, due to the Global Interpreter Lock (GIL), Python
threads are not truly parallel; they are useful for I/O-bound
tasks where threads spend a lot of time waiting for external
events (like network responses or file I/O).

Mehrdad Ahmadzadeh OS-Lab 1


Python

Multithreading

Mehrdad Ahmadzadeh OS-Lab 1


Python

Multiprocessing
The multiprocessing module allows the creation of separate
processes, each with its own Python interpreter and memory
space. This is effective for CPU-bound tasks since it bypasses
the GIL and allows for true parallelism.

Mehrdad Ahmadzadeh OS-Lab 1


Python

Multiprocessing

Mehrdad Ahmadzadeh OS-Lab 1


Python

Asyncio
The asyncio module provides a framework for writing
single-threaded concurrent code using coroutines. It is
particularly well-suited for I/O-bound tasks and allows you to
manage a large number of connections simultaneously with an
event loop.

Mehrdad Ahmadzadeh OS-Lab 1


Python

Asyncio

Mehrdad Ahmadzadeh OS-Lab 1


Python

Concurrent Futures
The concurrent.futures module provides a high-level interface
for asynchronously executing callables. It abstracts the use of
threads and processes and allows you to submit tasks and
retrieve their results.

Mehrdad Ahmadzadeh OS-Lab 1


Python

Concurrent Futures

Mehrdad Ahmadzadeh OS-Lab 1


Python
Concurrent Futures
Function that squares the input using ThreadPoolExecutor to run
concurrent_f function

Mehrdad Ahmadzadeh OS-Lab 1


Python

Concurrent Futures
_ = ...: The underscore (_) is a common convention in
Python to indicate that the result of the expression is not
going to be used. In this case, the program is effectively
ignoring the actual futures returned by as_completed.
However, this line ensures that the main thread will wait for
all submitted tasks to finish before moving on.

Mehrdad Ahmadzadeh OS-Lab 1


Python

Concurrent Futures

Mehrdad Ahmadzadeh OS-Lab 1


Python
Concurrent Futures
Starting with a large number.

Mehrdad Ahmadzadeh OS-Lab 1


Python
Concurrent Futures
Concurrent execution with a lock

Mehrdad Ahmadzadeh OS-Lab 1


Python

Concurrent Futures
CPU while running the code:

Mehrdad Ahmadzadeh OS-Lab 1


Python

Thread Class
To use threads you need import Thread using the following
code: from threading import Thread
To create a thread in Python you’ll want to make your class
work as a thread. For this, you should subclass your class
from the Thread class

Mehrdad Ahmadzadeh OS-Lab 1


Python

Threads
04-helloPythonWithThreads.py

Mehrdad Ahmadzadeh OS-Lab 1


Python

Threads
04-helloPythonWithThreads.py

Mehrdad Ahmadzadeh OS-Lab 1


Python

Threads
04-helloPythonWithThreads.py

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism

Threads
When using threads you must always make sure that you
never leave any thread running in the background.
This is very bad programming and can cause you all sorts of
pain when you work on bigger applications.

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism

Multithreading
The most widely used programming paradigm for the
management of concurrence in software applications is based
on multithreading.
Generally, an application is made by a single process that is
divided into multiple independent threads, which represent
activities of different types that run parallel and compete with
each other.

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism

Multithreading
All the existing operating systems support multithreading
In almost all programming languages, there are mechanisms
that you can use to implement concurrent applications
through the use of threads.
Multithreaded programming is a good choice to achieve
concurrent applications.

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism

Multithreading

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism

Main Elements of a thread


program counter
registers
stack

Shared resources
data
operating system resources

States of execution
ready
running
blocked

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism

Python thread management


Python manages a thread via the threading package that is
provided by the Python standard library.
The threading module provides several synchronization
mechanisms that are very simple to implement.

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism

Define a thread
The simplest way to use a thread is to instantiate it with a
target function and then call the start() method
class threading.Thread(group=None,
target=None,
name=None,
args=(),
kwargs={})

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism

Define a thread
group: This is the value of group that should be None; this is
reserved for future implementations
target: This is the function that is to be executed when you
start a thread activity
name: This is the name of the thread; by default, a unique
name of the form Thread-N is assigned to it
args: This is the tuple of arguments that are to be passed to
a target
kwargs: This is the dictionary of keyword arguments that are
to be used for the target function

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism
Define a thread
05-Thread.py

The thread does not start running until the start() method is
called
The method join() blocks the calling thread until the thread
whose join() method is called is terminated.
Mehrdad Ahmadzadeh OS-Lab 1
Thread-based Parallelism

Define a thread
06-Thread_definition.py

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism

Determine which thread is running


Using arguments to identify or name the thread is
cumbersome and unnecessary.
Each Thread instance has a name with a default value that
can be changed as the thread is created.
Naming threads is useful in server processes with multiple
service threads that handle different operations.

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism

Determine which thread is running


07-Thread_determine.py

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism

Determine which thread is running


07-Thread_determine.py

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism

Determine which thread is running


If the name is not defined, the default name will be used:

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism

Determine which thread is running


If you walk through the output carefully, you’ll see all three
threads getting started in the order you might expect, but in
this case they may finish in a different order!
The order in which threads are run is determined by the
operating system and can be quite hard to predict.
It may (and likely will) vary from run to run, so you need to be
aware of that when you design algorithms that use threading.

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism

Determine which thread is running


09-Thread_determine.py

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism

How to use a thread in a subclass


To implement a new thread using the threading module, you have
to do the following:
Define a new subclass of the Thread class
Override the _init__(self [,args]) method to add
additional arguments
Then, you need to override the run(self [,args]) method
to implement what the thread should do when it is started

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism

How to use a thread in a subclass


Once you have created the new Thread subclass, you can
create an instance of it and then start a new thread by
invoking the start() method, which will, in turn, call the run()
method.

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism

How to use a thread in a subclass


MyThreadClass.py

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism

How to use a thread in a subclass


MyThreadClass.py

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism

How to use a thread in a subclass


Each thread is represented by a class that extends the Thread
class and overrides its run() method
Calling the constructor of the Thread class is
mandatory—using it, we can redefine some properties of the
thread as the name or group of the thread
The thread is placed in the active state of the call to start()
and remains there until it ends the run() method or you throw
an unhandled exception to it.
The program ends when all the threads are terminated.
The join()command just handles the termination of threads.

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism

Thread synchronization with Lock and RLock


When a thread wants to access a portion of shared memory, it
must necessarily acquire a lock on that portion prior to using
it.
After completing its operation, the thread must release the
lock that was previously obtained so that a portion of the
shared memory is available for any other threads that want to
use it.

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism
Lock Example
11-lock.py

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism

Lock VS RLock
The default Lock doesn’t recognize which thread the lock
currently holds.
If the shared resource is being accessed by any thread then
other threads trying to access the shared resource will get
blocked even if it is the same thread that locked the shared
resource.
If a shared resource is in RLock then it can be called again
safely.

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism

Lock Example
13-lock.py

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism

Lock VS RLock
Please refer to 13-Rlock_2 and 13-Rlock_3 .py for more details.

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism

Deadlock
Using lock can often lead the execution to a bad situation of
deadlock.
A deadlock occurs due to the acquisition of a lock from
different threads
It is impossible to proceed with the execution of operations
since the various locks between them block access to the
resources.
.

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism

Deadlock

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism

Thread synchronization with semaphores


It can be said that Semaphore is an advanced version of Lock.
to using it.
Semaphore has a custom number to control multiple threads
to access resources.
But there is only one with Lock.

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism
Thread synchronization with semaphores
Whenever a thread wants to access a resource that is
associated with a semaphore, it must invoke the acquire()
operation, which decreases the internal variable of the
semaphore and allows access to the resource if the value of
this variable appears to be non-negative.
If the value is negative, the thread would be suspended and
the release of the resource by another thread will be placed on
hold.
Whenever a thread has finished using the data or shared
resource, it must release the resource through the release()
operation.
In this way, the internal variable of the semaphore is
incremented, and the first waiting thread in the semaphore’s
queue will have access to the shared resource.

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism

Thread synchronization with semaphores

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism

Thread synchronization with a condition


A condition identifies a change of state in the application.
This is a synchronization mechanism where a thread waits for
a specific condition and another thread notifies that this
condition has taken place.
Once the condition takes place, the thread acquires the lock
to get exclusive access to the shared resource.

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism

Thread synchronization with a condition


The class producer writes to a buffer as long as it is not full,
and the class consumer takes the data from the buffer , as
long as the buffer is not empty.
The class producer will notify the consumer that the buffer is
not empty, while the consumer will report to the producer
that the buffer is not full.

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism

Monitors
Monitors in the context of concurrent programming are
essentially a higher-level abstraction that combines locking
and condition variables to manage access to shared resources.

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism

Thread synchronization with a condition: 15-Condition

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism
Thread synchronization with a condition: 15-Condition.py

Mehrdad Ahmadzadeh OS-Lab 1


Thread-based Parallelism

Thread synchronization with a condition


It’s interesting to see the Python internals for the condition
synchronizations mechanism.
The internal class _Condition creates a RLock() object if no
existing lock is passed to the class’s constructor
Also, the lock will be managed when acquire() and released()
are called

Mehrdad Ahmadzadeh OS-Lab 1

You might also like