Unit 2
Unit 2
KATIKAM MAHESH
1.1
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
Process Control Block is a data structure that contains information of the process related to it.
The process control block is also known as a task control block, entry of the process table, etc.
It is very important for process management as the data structuring for processes is
done in terms of the PCB. It also defines the current state of the operating system.
The process control stores many data items that are needed for efficient process management.
Some of these data items are explained with the help of the given diagram.
Each process is represented in the operating system by a process control block also called a task
cont rol block.(PCB) Also called a task control block.
These are the different files that are associated with the process
The process priority, pointers to scheduling queues etc. is the CPU scheduling information that
is contained in the PCB. This may also include any other scheduling parameters.
The memory management information includes the page tables or the segment tables
depending on the memory system used. It also contains the value of the base registers,
limit registers etc.
Accounting information
The time limits, account numbers, amount of CPU used, process numbers etc. are all a
part of the PCB accounting information.
The process control block is kept in a memory area that is protected from the normal
user access. This is done because it contains important process information. Some of the
operating.systems place the PCB at the beginning of the kernel stack for the process as it is a safe
location.
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
Sometimes, the process might be using a round-robin scheduling algorithm where after every
fixed time quantum, the process has to come back to the ready state from the running state. So,
these process switchings are done with the help of Context Switching. In this blog, we will learn
about the concept of Context Switching in the Operating System and we will also learn about the
advantages and disadvantages of Context Switching. So, let's get started.
It is one of the essential features of the multitasking operating system. The processes are switched
so fastly that it gives an illusion to the user that all the processes are being executed at the same
time.
But the context switching process involved a number of steps that need to be followed. You can't
directly switch a process from the running state to the ready state. You have to save the context
of that process.
If you are not saving the context of any process P then after
some time, when the process P comes in the CPU for execution again, then the process will start
executing from starting. But in reality, it should continue from that point where it left the CPU in
its previous execution.
So, the context of the process should be saved before putting any other process in the running
state. A context is the contents of a CPU's registers and program counter at any point in time.
Context switching can happen due to the following reasons:•
When a process of high priority comes in the ready state. In this case, the execution
of the running process should be stopped and the higher priority process should be
given the CPU for execution. When an interruption occurs then the process in the running state
should be stopped and the CPU should handle the interrupt before doing something else.
When a transition between the user mode and kernel mode is required then you
have to perform the context switching.
Steps involved in Context Switching
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
The process of context switching involves a number of steps. The following diagram depicts the
process of context switching between the two processes P1 and P2.
In the above figure, you can see that initially, the process P1 is in the running state and the process
P2 is in the ready state. Now, when some interruption occurs then you have to switch the process
P1 from running to the ready state after saving the context and the process P2 from ready to
running state. The following steps will be performed:
1.
Firstly, the context of the process P1 i.e. the process present in the running state will
be saved in the Process Control Block of process P1 i.e. PCB1.
2.
Now, you have to move the PCB1 to the relevant queue i.e. ready queue, I/O queue,
waiting queue, etc.
3.
From the ready state, select the new process that is to be executed i.e. the process
P2.
4.
Now, update the Process Control Block of process P2 i.e. PCB2 by setting the
process state to running. If the process P2 was earlier executed by the CPU, then
you can get the position of last executed instruction so that you can resume the
execution of P2.
5.
Similarly, if you want to execute the process P1 again, then you have to follow the
same steps as mentioned above(from step 1 to 4).
For context switching to happen, two processes are at least required in general, and in the case of
the round-robin algorithm, you can perform context switching with the help of one process only.
The time involved in the context switching of one process by other is called the
Context Switching Time
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
Preemptive Scheduling
In Preemptive Scheduling, the tasks are mostly assigned with their priorities.
Sometimes it is important to run a task with a higher priority before another lower
priority task, even if the lower priority task is still running. The lower priority task
holds for some time and resumes when the higher priority task finishes its execution.
Non-Preemptive Scheduling
In this type of scheduling method, the CPU has been allocated to a specific process.
The process that keeps the CPU busy will release the CPU either by switching context
or terminating. It is the only method that can be used for various hardware platforms.
That's because it doesn't need special hardware (for example, a timer) like preemptive
scheduling.
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
What is Dispatcher?
It is a module that provides control of the CPU to the process. The Dispatcher should
be fast so that it can run on every context switch. Dispatch latency is the amount of
time needed by the CPU scheduler to stop one process and start another.
Functions performed by Dispatcher:
•
Context Switching
•
Switching to user mode
•
Moving to the correct location in the newly loaded program.
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
Sheduling algorithems
1. First Come First Serve
First Come First Serve is the full form of FCFS. It is the easiest and most simple CPU
scheduling algorithm. In this type of algorithm, the process which requests the CPU
gets the CPU allocation first. This scheduling method can be managed with a FIFO
queue.
As the process enters the ready queue, its PCB (Process Control Block) is linked with
the tail of the queue. So, when CPU becomes free, it should be assigned to the process
at the beginning of the queue.
Characteristics of FCFS method:
•
It offers non-preemptive and pre-emptive scheduling algorithm.
•
Jobs are always executed on a first-come, first-serve basis
•
It is easy to implement and use.
•
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
However, this method is poor in performance, and the general wait time is
quite high.
First Come First Serve (FCFS)
•
Jobs are executed on first come, first serve basis.
•
It is a non-preemptive, pre-emptive scheduling algorithm.
•
Easy to understand and implement.
•
Its implementation is based on FIFO queue.
•
Poor in performance as average wait time is high.
In FCFS Scheduling,
⚫
The process which arrives first in the ready queue is firstly assigned the CPU.
⚫
In case of a tie, process with smaller process id is executed first.
⚫
It is always non-preemptive in nature.
divantages-
⚫
It is simple and easy to understand.
⚫
It can be easily implemented using queue data structure.
⚫
It does not lead to starvation.
Disadvantages-It does not consider the priority or burst time of the processes.
⚫ It suffers from convoy effect.
Convoy Effect
In convoy effect,
•
Consider processes with higher burst time arrived before the processes with
smaller burst time.
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
This is not an ideal method to implement it in a shared system where the required CPU time is
unknown.
• Associate with each process as the length of its next CPU burst. So that operating system
usethese lengths, which helps to schedule the process with the shortest possible time.
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
4. Round-Robin Scheduling
Round robin is the oldest, simplest scheduling algorithm. The name of this algorithm comes
from the
round-robin principle, where each person gets an equal share of something in turn. It is mostly
used for
scheduling algorithms in multitasking. This algorithm method helps for starvation free execution
of
processes.
Characteristics of Round-Robin Scheduling
•
Round robin is a hybrid model which is clock-driven
•
Time slice should be minimum, which is assigned for a specific task to be processed. However,
it may vary for different processes.
•
It is a real time system which responds to the event within a specific time limit.
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
Scheduling
A new job enters queue Q0 which is served FCFS. When it gains CPU, job receives 8
milliseconds. If it
does not finish in 8 milliseconds, job is moved to queue Q1.
At Q1 job is again served FCFS and receives 16 additional milliseconds. If it still does not
complete, it
is preempted and moved to queue Q2.
Multilevel Feedback Queues
regular intervals and place them all in the highest priority queue.
What is the need of such complex Scheduling?
•
Firstly, it is more flexible than the multilevel queue scheduling.
•
To optimize turnaround time algorithms like SJF is needed which require the
running time of processes to schedule them. But the running time of the process is
not known in advance. MFQS runs a process for a time quantum and then it can
change its priority(if it is a long process). Thus it learns from past behavior of the
process and then predicts its future behavior.This way it tries to run shorter
process first thus optimizing turnaround time.
•
MFQS also reduces the response time.
Example –
Consider a system which has a CPU bound process, which requires the burst time of
40 seconds.The multilevel Feed Back Queue scheduling algorithm is used and the
queue time quantum ‘2’ seconds and in each level it is incremented by ‘5’
seconds.Then how many times the process will be interrupted and on which queue
the process will terminate the execution?
Solution –
Process P needs 40 Seconds for total execution.
At Queue 1 it is executed for 2 seconds and then interrupted and shifted to queue 2.
At Queue 2 it is executed for 7 seconds and then interrupted and shifted to queue 3.
At Queue 3 it is executed for 12 seconds and then interrupted and shifted to queue
4.
At Queue 4 it is executed for 17 seconds and then interrupted and shifted to queue
5.
At Queue 5 it executes for 2 seconds and then it completes.
Hence the process is interrupted 4 times and completes on queue 5.
Advantages:
1.
It is more flexible.
2.
It allows different processes to move between different queues.
3.
It prevents starvation by moving a process that waits too long for lower
priority queue to the higher priority queue.
Disadvantages:
1.
For the selection of the best scheduler, it require some other means to select
the values.
2.
It produces more CPU overheads.
3.
It is most complex algorithm.
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
On UNIX, a listing of processes can be obtained using the ps command. For example, entering
the command ps -e l will list complete information for all processes currently active in the system.
It is easy to construct a process tree similar to what is shown in Figure by recursively tracing
parent processes all the way to the ini t process. In general, a process will need certain resources
(CPU time, memory, files, I/O devices) to accomplish its task. When a process creates a
subprocess, that subprocess may be able to obtain its resources directly from the operatiiig
system, or it may be constrained to a subset of the resources of the parent process.
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
The parent may have to partition its resources among its children, or it may be able to share some
resources (such as memory or files) among several of its children. Restricting a child process to
a subset of the parent's resources prevents any process from overloading the system by creating
too many subprocesses. In addition to the various physical and logical resources that a process
obtains when it is created, initialization data (input) may be passed along by the parent process
to the child process. For example, consider a process whose function is to display the contents
of a file—say, img.jpg—on the screen of a terminal. When it is created, it will get, as an input
from its parent process, the name of the file img.jpg, and it will use that file name, open the file,
and write the contents out. It may also get the name of the output device. Some operating systems
pass resources to child processes. On such a system, the new process may get two open files,
img.jpg and the terminal device, and may simply transfer the datum between the two. When a
process creates a new process, two possibilities exist in terms of execution:
1. The parent continues to execute concurrently with its children.
2. The parent waits until some or all of its children have terminated.
There are also two possibilities in terms of the address space of the new process:
1. The child process is a duplicate of the parent process (it has the same program and data as the
parent).
2. The child process has a new program loaded into it. To illustrate these differences, let's first
consider the UNIX operating system. In UNIX, as we've seen, each process is identified by its
process identifier.
A new process is created by the forkO system call. The new process consists of a copy of the
address space of the original process. This mechanism allows the parent process to communicate
easily with its child process. Both processes (the parent and the child) continue execution at the
instruction after the f ork(), with one difference: The return code for the forkO is zero for the new
(child) process, whereas the (nonzero) process identifier of the child is returned to the parent.
Typically, the execO system call is used after a forkO system call by one of the two processes
to replace the process's memory space with a new program. The exec ()
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
system call loads a binary file into memory (destroying the memory image of the program
containing the execO system call) and starts its execution. In this manner, the two processes are
able to communicate and then go their separate ways. The parent can then create more children;
or, if it has nothing else to do while the child runs, it can issue a wait () system call to move itself
off the ready queue until the termination of the child.
The UNIX system calls previously described. We now have two different processes running a
copy of the same program. The value of pid for the child process is zero; that for the parent is an
integer value greater than zero. The child process overlays its address space with the UNIX
command /bin/Is (used to get a directory listing) using the execlpO system call (execlpO is a
version of the execO system call). The parent waits for the child process to complete with the
wait () system call. When the child process completes (by either implicitly or explicitly invoking
exit ()) the parent process resumes from the call to wait (), where it completes using the exit ()
system call.. As an alternative example, we next consider process creation in Windows. Processes
are created in the Win32 API using the CreateProcessO function, which is similar to f ork () in
that a parent creates a new child process. However, whereas f ork () has the child process
inheriting the address space of its parent, CreateProcess () requires loading a specified program
into the address space of the child process at process creation. Furthermore, whereas fork () is
passed no parameters, CreateProcess 0 expects no fewer than ten parameters
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
passed to CreateProcess () are the application name and command line parameters. If the
application name is NULL (which in this case it is), the command line parameter specifies the
application to load. In this instance we are loading the Microsoft Windows
mspaint.exeapplication.
Beyond these two initial parameters, we use the default parameters for inheriting process and
thread handles as well as specifying no creation flags. We also use the parent's existing
environment block and starting directory. Last, we provide two pointers to the STARTUPINFO
and PROCESS-INFORMATION structures created at the beginning of the program.The parent
process waits for the child to complete by invoking the waitO system call. The equivalent of this
in Win32 is WaitForSingleObj ect (), which is passed a handle of the child process—pi .
hProcess— that it is waiting for to complete. Once the child process exits, control returns from
the WaitForSingleOb j ect () function in the parent process.
Process Termination
A process terminates when it finishes executing its final statement and asks the operating system
to delete it by using the exit () system call. At that point, the process may return a status value
(typically an integer) to its parent process (via the wait() system call). All the resources of the
process—including physical and virtual memory, open files, and I/O buffers—are deallocated by
the operating system. Termination can occur in other circumstances as well. A process can cause
the termination of another process via an appropriate system call (for example,
TerminateProcessO in Win32). Usually, such a system call can be invoked only by the parent of
the process that is to be terminated. Otherwise, users could arbitrarily kill each other's jobs. Note
that a parent needs to know the identities of its children. Thus, when one process creates a new
process, the identity of the newly created process is passed to the parent. A parent may terminate
the execution of one of its children for a variety of reasons, such as these:
• The child has exceeded its usage of some of the resources that it has been allocated. (To
determine whether this has occurred, the parent must have a mechanism to inspect the state of its
children.)
• The task assigned to the child is no longer required.
• The parent is exiting, and the operating system does not allow a child to continue if its parent
terminates. Some systems, including VMS, do not allow a child to exist if its parent has
terminated. In such systems, if a process terminates (either normally or abnormally), then all its
children must also be terminated. This phenomenon, referred to as cascading termination, is
normally initiated by the operating system.
To illustrate process execution and termination, consider that, in UNIX, we can terminate a
process by using the exitQ system call; its parent process may wait for the termination of a child
process by using the waitO system call. The wait () system call returns the process identifier of a
terminated child so that the parent can tell which of its possibly many children has terminated. If
the parent terminates, however, all its children have assigned as their new parent the ini t process.
Thus, the children still have a parent to collect their status and execution statistics.
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
#define buff_max 25
#define mod %
struct item{
while(1){
shared_buff[free_index] = nextProduced;
free_index = (free_index + 1) mod buff_max;
}
Consumer Process Code item nextConsumed;
while(1){
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
nextConsumed = shared_buff[full_index];
full_index = (full_index + 1) mod buff_max;
}
ii) Messaging Passing Method
Now, We will start our discussion of the communication between processes via message passing.
In this method, processes communicate with each other without using any kind of shared memory.
If two processes p1 and p2 want to communicate with each other, they proceed as follows:
Establish a communication link (if a link already exists, no need to establish it again.)
Start exchanging messages using basic primitives.
We need at least two primitives:
– send(message, destination) or send(message)
– receive(message, host) or receive(message)
The message size can be of fixed size or of variable size. If it is of fixed size, it is easy for an OS
designer but complicated for a programmer and if it is of variable size then it is easy for a
programmer but complicated for the OS designer. A standard message can have two
parts: header and body.
The header part is used for storing message type, destination id, source id, message length,
and control information. The control information contains information like what to do if runs
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
out of buffer space, sequence number, priority. Generally, message is sent using FIFO style.
int item;
Message m;
while(1){
receive(Consumer, &m);
item = produce();
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
build_message(&m , item ) ;
send(Consumer, &m);
}
}
Consumer Code
void Consumer(void){
int item;
Message m;
while(1){
receive(Producer, &m);
item = extracted_item();
send(Producer, &m);
consume_item(item);
}
}
Examples of IPC systems
Pipe
Socket
Remote Procedural calls (RPCs)
Client/Server communication involves two components, namely a client and a server. They are
usually multiple clients in communication with a single server. The clients send requests to the
server and the server responds to the client requests.
There are three main methods to client/server communication. These are given as follows −
Sockets
Sockets facilitate communication between two processes on the same machine or different
machines. They are used in a client/server framework and consist of the IP address and port
number. Many application protocols use sockets for data connection and data transfer between a
client and a server.
Socket communication is quite low-level as sockets only transfer an unstructured byte stream
across processes. The structure on the byte stream is imposed by the client and server applications.
A diagram that illustrates sockets is as follows −
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
Pipes
These are interprocess communication methods that contain two end points. Data is entered
from one end of the pipe by a process and consumed from the other end by the other process.
The two different types of pipes are ordinary pipes and named pipes. Ordinary pipes only allow
one way communication. For two way communication, two pipes are required. Ordinary pipes
have a parent child relationship between the processes as the pipes can only be accessed by
processes that created or inherited them.
Named pipes are more powerful than ordinary pipes and allow two way communication. These
pipes exist even after the processes using them have terminated. They need to be explicitly deleted
when not required anymore.
A diagram that demonstrates pipes are given as follows −
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
TOPIC-6:Multithreaded Programming:
6:1 : Multithreading models,
6:2: Thread libraries,
6:3 Threading issues.
6:4 Thread scheduling.
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
In the remainder of this section, we describe basic thread creation using these three
thread libraries. As an illustrative example, we design a multithreaded program that
performs the summation of a non-negative integer in a separate thread using the well
known summation function. For example, if N were 5, this function would represent
the summation from 0 to 5, which is 15. Each of the three programs will be run with
the upper bounds of the summation entered on the command line; thus, if the user
enters 8, the summation of the integer values from 0 to 8 will be output.
Pthreads
Pthreads refers to the POSIX standard (IEEE 1003.1c) defining an API for thread
creation and synchronization. This is a specification for thread behavior, not an
implementation. Operating system designers may implement the specification in any
way they wish. Numerous systems implement the Pthreads specification, including
Solaris, Linux, Mac OS X, and Tru64 UNIX. Shareware implementations are
available in the public domain for the various Windows operating systems as well. In
a Pthreads program, separate threads begin execution in a specified function, this is
the runner () function. When this program begins, a single thread of control begins in
main().
After some initialization, main() creates a second thread that begins control in the
runner () function. Both threads share the global data sum. Let's look more closely at
this program. All Pthreads programs must include the pthread.h header file. The
statement pthreadjt tid declares the identifier for the thread we will create. Each
thread has a set of attributes, including stack size and scheduling information. The
pthread_attr_t attr declaration represents the attributes for the thread. We set the
attributes in the function call pthread_attr_init C&attr). Because we did not explicitly
set any attributes, we use the default attributes provided. A separate thread is created
with the pthread_create () function call. In addition to passing the thread identifier
and the attributes for the thread, we also pass the name of the function where the new
thread will begin execution-—in this case, the runner () function. Last, we pass the
integer parameter that was provided on the command line, argv [1]. At this point, the
program has two threads: the initial (or parent) thread in main() and the summation
(or child) thread performing the summation operation in the runner () function. After
creating the summation thread, the parent thread will wait for it to complete by
calling the pthread_join() function. The summation thread will complete when it
calls the function pthread.exit() . Once the summation thread has returned, the parent
thread will output the value of the shared data sum.
Win32 Threads
The technique for creating threads using the Win32 thread library is similar to the
Pthreads technique in several ways. we must include the windows.h header file when
using the Win32 API. Just as in the Pthreads, data shared by the separate threads—in
this case, Sum—are declared globally (the DWORD data type is an unsigned 32-bit
integer. We also define the SummationO function that is to be performed in a
separate thread. This function is passed a pointer to a void, which Win32 defines as
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
LPVOID. The thread performing this function sets the global data Sum to the value
of the summation from 0 to the parameter passed to SummationO.
Threads are created in the Win32 API using the CreateThreadO function and—just
as in Pthreads—a set of attributes for the thread is passed to this function. These attributes
include security information, the size of the stack, and a flag that can be set
to indicate if the thread is to start in a suspended state. In this program, we use the
default values for these attributes (which do not initially set the thread to a suspended
state and instead make it eligible to be run by the CPU scheduler). Once the
summation thread is created, the parent must wait for it to complete before outputting
the value of Sum, as the value is set by the summation thread. Recall that the Pthread
program had the parent thread wait for the summation thread using the pthread join()
statement. We perform the equivalent of this in the Win32 API using the
WaitForSingleObject () function, which causes the creating thread to block until the
summation thread has exited.
Java Threads
Threads are the fundamental model of program execution in a Java program, and the
Java language and its API provide a rich set of features for the creation and
management of threads. All Java programs comprise at least a single thread, even a
simple Java program consisting of only a main() method runs as a single thread in the
JVM. There are two techniques for creating threads in a Java program. One approach
is to create a new class that is derived from the Thread class and to override its run()
method. An alternative—and more commonly used— technique is to define a class
that implements the Runnable interface.
Q: If one thread forks, is the entire process copied, or is the new process
single-threaded?
A: System dependant.
A: If the new process execs right away, there is no need to copy all the
other threads. If it doesn't, then the entire process should be copied.
A: Many versions of UNIX provide multiple versions of the fork call for
this purpose.
Most data is shared among threads, and this is one of the major benefits of
using threads in the first place.
However sometimes threads need thread-specific data also.
Most major thread libraries ( pThreads, Win32, Java ) provide support for
thread-specific data, known as thread-local storage or TLS. Note that
this is more like static data than local variables,because it does not cease
to exist when the function ends.
handler. The upcall also provides a new LWP for the upcall
handler to run on, which it can then use to reschedule the user
thread that is about to become blocked. The OS will also issue
upcalls when a thread becomes unblocked, so the thread library
can make appropriate adjustments.
If the kernel thread blocks, then the LWP blocks, which blocks the user
thread.
Ideally there should be at least as many LWPs available as there could be
concurrently blocked kernel threads. Otherwise if all LWPs are blocked,
then user threads will have to wait for one to become available.
In real-time, the first boundary of thread scheduling is beyond specifying the scheduling policy
and the priority. It requires two controls to be specified for the User level threads: Contention
scope, and Allocation domain. These are explained as following below.
1. Contention Scope :
The word contention here refers to the competition or fight among the User level threads to access
the kernel resources. Thus, this control defines the extent to which contention takes place. It is
defined by the application developer using the thread library. Depending upon the extent of
contention it is classified as Process Contention Scope and System Contention Scope.
1. Process Contention Scope (PCS) –
The contention takes place among threads within a same process. The thread library schedules
the high-prioritized PCS thread to access the resources via available LWPs (priority as
specified by the application developer during thread creation).
2. System Contention Scope (SCS) –
The contention takes place among all threads in the system. In this case, every SCS thread
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
is associated to each LWP by the thread library and are scheduled by the system scheduler to
access the kernel resources.
In LINUX and UNIX operating systems, the POSIX Pthread library provides a function
Pthread_attr_setscope to define the type of contention scope for a thread during its creation.
3.
int Pthread_attr_setscope(pthread_attr_t *attr, int scope)
4.
The first parameter denotes to which thread within the process the scope is defined.
The second parameter defines the scope of contention for the thread pointed. It takes two
values.
5.
PTHREAD_SCOPE_SYSTEM
PTHREAD_SCOPE_PROCESS
6.
If the scope value specified is not supported by the system, then the function returns ENOTSUP.
7.
2. Allocation Domain :
The allocation domain is a set of one or more resources for which a thread is competing. In a
multicore system, there may be one or more allocation domains where each consists of one or
more cores. One ULT can be a part of one or more allocation domain. Due to this high complexity
in dealing with hardware and software architectural interfaces, this control is not specified. But
by default, the multicore system will have an interface that affects the allocation domain of a
thread.
Consider a scenario, an operating system with three process P1, P2, P3 and 10 user level
threads (T1 to T10) with a single allocation domain. 100% of CPU resources will be distributed
among all the three processes. The amount of CPU resources allocated to each process and to each
thread depends on the contention scope, scheduling policy and priority of each thread defined by
the application developer using thread library and also depends on the system scheduler. These
User level threads are of a different contention scope.
In this case, the contention for allocation domain takes place as follows,
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
1. Process P1:
All PCS threads T1, T2, T3 of Process P1 will compete among themselves. The PCS threads of
the same process can share one or more LWP. T1 and T2 share an LWP and T3 are allocated to
a separate LWP. Between T1 and T2 allocation of kernel resources via LWP is based on
preemptive priority scheduling by the thread library. A Thread with a high priority will preempt
low priority threads. Whereas, thread T1 of process p1 cannot preempt thread T3 of process
p3 even if the priority of T1 is greater than the priority of T3. If the priority is equal, then the
allocation of ULT to available LWPs is based on the scheduling policy of threads by the system
scheduler(not by thread library, in this case).
2. Process P2:
Both SCS threads T4 and T5 of process P2 will compete with processes P1 as a whole and with
SCS threads T8, T9, T10 of process P3. The system scheduler will schedule the kernel resources
among P1, T4, T5, T8, T9, T10, and PCS threads (T6, T7) of process P3 considering each as a
separate process. Here, the Thread library has no control of scheduling the ULT to the kernel
resources.
3. Process P3:
Combination of PCS and SCS threads. Consider if the system scheduler allocates 50% of CPU
resources to process P3, then 25% of resources is for process scoped threads and the remaining
25% for system scoped threads. The PCS threads T6 and T7 will be allocated to access the 25%
resources based on the priority by the thread library. The SCS threads T8, T9, T10 will divide
the 25% resources among themselves and access the kernel resources via separate LWP and
KLT. The SCS scheduling is by the system scheduler.
Note:
For every system call to access the kernel resources, a Kernel Level thread is created and
associated to separate LWP by the system scheduler.
Number of Kernel Level Threads = Total Number of LWP
Total Number of LWP = Number of LWP for SCS + Number of LWP for PCS
Number of LWP for SCS = Number of SCS threads
Number of LWP for PCS = Depends on application developer
Here,
Number of SCS threads = 5
Number of LWP for PCS = 3
Number of SCS threads = 5
Number of LWP for SCS = 5
Total Number of LWP = 8 (=5+3)
Number of Kernel Level Threads = 8
Advantages of PCS over SCS :
If all threads are PCS, then context switching, synchronization, scheduling everything
takes place within the userspace. This reduces system calls and achieves better performance.
PCS is cheaper than SCS.
PCS threads share one or more available LWPs. For every SCS thread, a separate LWP is
associated.For every system call, a separate KLT is created.
The number of KLT and LWPs created highly depends on the number of SCS threads
created. This increases the kernel complexity of handling scheduling and synchronization.
Thereby, results in a limitation over SCS thread creation, stating that, the number of SCS threads
to be smaller than the number of PCS threads.
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
If the system has more than one allocation domain, then scheduling and synchronization
of resources becomes more tedious. Issues arise when an SCS thread is a part of more than one
allocation domain, the system has to handle n number of interfaces.
The second boundary of thread scheduling involves CPU scheduling by the system scheduler. The
scheduler considers each kernel-level thread as a separate process and provides access to the
kernel resources.
Difference between
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
TOPIC:7
7:5 Mutexes,
7:6Monitors,
7:8Barriers,
7:9 Classical IPC Problems - Dining philosophers problem, Readers and writers problem
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
Background
item nextProduced;
while( true ) {
item nextConsumed;
while( true ) {
while( in == out )
; /* Do nothing */
The only problem with the above code is that the maximum number of
items which can be placed into the buffer is BUFFER_SIZE - 1. One slot
is unavailable because there always has to be a gap between the producer
and the consumer.
We could try to overcome this deficiency by introducing a counter variable,
as shown in the following code segments:
Unfortunately we have now introduced a new problem, because both the producer and the
consumer are adjusting the value of the variable counter, which can lead to a condition
known as a race condition. In this condition a piece of code may or may not
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
work correctly, depending on which of two simultaneous processes executes first, and
more importantly if one of the processes gets interrupted such that the other process runs
between important steps of the first process. ( Bank balance example discussed in class. )
The particular problem above comes from the producer executing "counter++" at the same
time the consumer is executing "counter--". If one process gets part way through making
the update and then the other process butts in, the value of counter can get left in an
incorrect state.
But, you might say, "Each of those are single instructions - How can they get interrupted
halfway through?" The answer is that although they are single instructions in C++, they
are actually three steps each at the hardware level: (1) Fetch counter from memory into a
register, (2) increment or decrement the register, and (3) Store the new value of counter
back to memory. If the instructions from the two processes get interleaved, there could be
serious problems, such as illustrated by the following:
o The code following the critical section is termed the exit section. It generally
releases the lock on someone else's door, or at least lets the world know that they
are no longer in their critical section.
o The rest of the code not included in either the critical section or the entry or exit
sections is termed the remainder section.
o
o Figure 5.1 - General structure of a typical process Pi
A solution to the critical section problem must satisfy the following three conditions:
1. Mutual Exclusion - Only one process at a time can be executing in their critical
section.
2. Progress - If no process is currently executing in their critical section, and one or
more processes want to execute their critical section, then only the processes not
in their remainder sections can participate in the decision, and the decision cannot
be postponed indefinitely. ( I.e. processes cannot be blocked forever waiting to get
into their critical sections. )
3. Bounded Waiting - There exists a limit as to how many other processes can get
into their critical sections after a process requests entry into their critical section
and before that request is granted. ( I.e. a process requesting entry into their critical
section will get a turn eventually, and there is a limit as to how many other
processes get to go first. )
We assume that all processes proceed at a non-zero speed, but no assumptions can be made
regarding the relative speed of one process versus another.
Kernel processes can also be subject to race conditions, which can be especially
problematic when updating commonly shared kernel data structures such as open file tables
or virtual memory management. Accordingly kernels can take on one of two forms:
2. Preemptive kernels allow for real-time operations, but must be carefully written to
avoid race conditions. This can be especially tricky on SMP systems, in which
multiple kernel processes may be running simultaneously on different processors.
Non-preemptive kernels include Windows XP, 2000, traditional UNIX, and Linux prior
to 2.6; Preemptive kernels include Linux 2.6 and later, and some commercial UNIXes such
as Solaris and IRIX
Peterson's Solution
o In the entry section, process i first raises a flag indicating a desire to enter the
critical section.
o Then turn is set to j to allow the other process to enter their critical section if
process j so desires.
o The while loop is a busy loop ( notice the semicolon at the end ), which makes
process i wait as long as process j has the turn and wants to enter the critical section.
o Process i lowers the flag[ i ] in the exit section, allowing process j to continue if it
has been waiting.
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
To prove that the solution is correct, we must examine the three conditions listed above:
1. Mutual exclusion - If one process is executing their critical section when the other
wishes to do so, the second process will become blocked by the flag of the first
process. If both processes attempt to enter at the same time, the last process to
execute "turn = j" will be blocked.
2. Progress - Each process can only be blocked at the while if the other process wants
to use the critical section ( flag[ j ] = = true ), AND it is the other process's turn to
use the critical section ( turn = = j ). If both of those conditions are true, then the
other process ( j ) will be allowed to enter the critical section, and upon exiting the
critical section, will set flag[ j ] to false, releasing process i. The shared variable
turn assures that only one process at a time can be blocked, and the flag variable
allows one process to release the other when exiting their critical section.
3. Bounded Waiting - As each process enters their entry section, they set the turn
variable to be the other processes turn. Since no process ever sets it back to their
own turn, this ensures that each process will have to let the other process go first
at most one time before it becomes their turn again.
Note that the instruction "turn = j" is atomic, that is it is a single machine instruction which
cannot be interrupted.
To generalize the solution(s) expressed above, each process when entering their critical
section must set some sort of lock, to prevent other processes from entering their critical
sections simultaneously, and must release the lock when exiting their critical section, to
allow other processes to proceed. Obviously it must be possible to attain the lock only
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
when no other process has already set a lock. Specific implementations of this general
procedure can get quite complicated, and may include hardware solutions as outlined in
this section.
One simple solution to the critical section problem is to simply prevent a process from
being interrupted while in their critical section, which is the approach taken by non
preemptive kernels. Unfortunately this does not work well in multiprocessor
environments, due to the difficulties in disabling and the re-enabling interrupts on all
processors. There is also a question as to how this approach affects timing if the clock
interrupt is disabled.
Another approach is for hardware to provide certain atomic operations. These operations
are guaranteed to operate as a single instruction, without interruption. One such operation
is the "Test and Set", which simultaneously sets a boolean lock variable and returns its
previous value, as shown in Figures 5.3 and 5.4:
The above examples satisfy the mutual exclusion requirement, but unfortunately do not
guarantee bounded waiting. If there are multiple processes trying to get into their critical
sections, there is no guarantee of what order they will enter, and any one process could
have the bad luck to wait forever until they got their turn in the critical section. ( Since
there is no guarantee as to the relative rates of the processes, a very fast process could
theoretically release the lock, whip through their remainder section, and re-lock the lock
before a slower process got a chance. As more and more processes are involved vying for
the same resource, the odds of a slow process getting locked out completely increase. )
Figure 5.7 illustrates a solution using test-and-set that does satisfy this requirement, using
two shared data structures, boolean lock and boolean waiting[ N ], where N is the number
of processes in contention for critical sections:
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
The key feature of the above algorithm is that a process blocks on the AND of the critical
section being locked and that this process is in the waiting state. When exiting a critical
section, the exiting process does not just unlock the critical section and let the other
processes have a free-for-all trying to get in. Rather it first looks in an orderly progression
( starting with the next process on the list ) for a process that has been waiting, and if it
finds one, then it releases that particular process from its waiting state, without unlocking
the critical section, thereby allowing a specific process into the critical section while
continuing to block all the others. Only if there are no other processes currently waiting is
the general lock removed, allowing the next process to come along access to the critical
section.
Unfortunately, hardware level locks are especially difficult to implement in multi-
processor architectures. Discussion of such issues is left to books on advanced computer
architecture.
Mutual exclusion is a mechanism to ensure that only one process (or person) is doing
certain things at one time, thus avoid data inconsistency. All others should be prevented
from modifying shared data until the current process finishes
Strict Alternation (see Fig. 2.11)
o the two processes strictly alternate in entering their CR
o the integer variable turn, initially 0, keeps track of whose turn is to enter the critical
region
o busy waiting, continuously testing a variable until some value appears, a lock that
uses busy waiting is called a spin lock
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
Topic 7:4
In order to read and write, both of them are usinga buffer. The code that simulates the sleep and
wake mechanism in terms of providing the solution to producer consumer problem is shown
below.
The producer produces the item and inserts it into the buffer. The value of the global variable
count got increased at each insertion. If the buffer is filled completely and no slot is available then
the producer will sleep, otherwise it keep inserting.
On the consumer's end, the value of count got decreased by 1 at each consumption. If the buffer
is empty at any point of time then the consumer will sleep otherwise, it keeps consuming the items
and decreasing the value of count by 1.
The consumer will be waked up by the producer if there is at least 1 item available in the buffer
which is to be consumed. The producer will be waked up by the consumer if there is at least one
slot available in the buffer so that the producer can write that.
Well, the problem arises in the case when the consumer got preempted just before it was about to
sleep. Now the consumer is neither sleeping nor consuming. Since the producer is not aware of
the fact that consumer is not actually sleeping therefore it keep waking the consumer while the
consumer is not responding since it is not sleeping.
This leads to the wastage of system calls. When the consumer get scheduled again, it will sleep
because it was about to sleep when it was preempted.
The producer keep writing in the buffer and it got filled after some time. The producer will also
sleep at that time keeping in the mind that the consumer will wake him up when there is a slot
available in the buffer.
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
The consumer is also sleeping and not aware with the fact that the producer will wake him up.
Let's examine the basic model that is sleep and wake. Assume that we have two system calls
as sleep and wake. The process which calls sleep will get blocked while the process which calls
will get waked up.
There is a popular example called producer consumer problem which is the most popular
problem simulating sleep and wake mechanism.
The concept of sleep and wake is very simple. If the critical section is not empty then the process
will go and sleep. It will be waked up by the other process which is currently executing inside the
critical section so that the process can get inside the critical section.
In producer consumer problem, let us say there are two processes, one process writes something
while the other process reads that. The process which is writing something is called
producer while the process which is reading is called consumer.
This is a kind of deadlock where neither producer nor consumer is active and waiting for each
other to wake them up. This is a serious problem which needs to be addressed.
Topic:7:5 Mutexes
Mutex Locks
The hardware solutions presented above are often difficult for ordinary programmers to
access, particularly on multi-processor machines, and particularly because they are often
platform-dependent.
Therefore most systems offer a software API equivalent called mutex locks or simply
mutexes. ( For mutual exclusion )
The terminology when using mutexes is to acquire a lock prior to entering a critical
section, and to release it when exiting, as shown in Figure 5.8:
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
Just as with hardware locks, the acquire step will block the process if the lock is in use by
another process, and both the acquire and release operations are atomic.
Acquire and release can be implemented as shown here, based on a boolean variable
"available":
Semaphores
A more robust alternative to simple mutexes is to use semaphores, which are integer
variables for which only two ( atomic ) operations are defined, the wait and signal
operations, as shown in the following figure.
Note that not only must the variable-changing steps ( S-- and S++ ) be indivisible, it is also
necessary that for the wait operation when the test proves false that there be no
interruptions before S gets decremented. It IS okay, however, for the busy loop to be
interrupted when the test is true, which prevents the system from hanging forever.
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
Semaphore Usage
Counting semaphores can take on any integer value, and are usually used to count the
number remaining of some limited resource. The counter is initialized to the number of
such resources available in the system, and whenever the counting semaphore is greater
than zero, then a process can enter a critical section and use one of the resources. When
the counter gets to zero ( or negative in some implementations ), then the process blocks
until another process frees up a resource and increments the counting semaphore with a
signal call. ( The binary semaphore can be seen as just a special case where the number of
resources initially available is just one. )
Semaphores can also be used to synchronize certain operations between processes. For
example, suppose it is important that process P1 execute statement S1 before process P2
executes statement S2.
o First we create a semaphore named synch that is shared by the two processes, and
initialize it to zero.
o Then in process P1 we insert the code:
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
S1;
signal( synch );
o
o and in process P2 we insert the code:
wait( synch );
S2;
o
o Because synch was initialized to 0, process P2 will block on the wait until after
P1 executes the call to signal.
Semaphore Implementation
The big problem with semaphores as described above is the busy loop in the wait call,
which consumes CPU cycles without doing any useful work. This type of lock is known
as a spinlock, because the lock just sits there and spins while it waits. While this is
generally a bad thing, it does have the advantage of not invoking context switches, and so
it is sometimes used in multi-processing systems when the wait time is expected to be
short - One thread spins on one processor while another completes their critical section on
another processor.
An alternative approach is to block a process when it is forced to wait for an available
semaphore, and swap it out of the CPU. In this implementation each semaphore needs to
maintain a list of processes that are blocked waiting for it, so that one of the processes can
be woken up and swapped back in when the semaphore becomes available. (
Whether it gets swapped back into the CPU immediately or whether it needs to hang out
in the ready queue for a while is a scheduling problem. )
The new definition of a semaphore and the corresponding wait and signal operations are
shown as follows:
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
Note that in this implementation the value of the semaphore can actually become negative,
in which case its magnitude is the number of processes waiting for that semaphore. This
is a result of decrementing the counter before checking its value.
Key to the success of semaphores is that the wait and signal operations be atomic, that is
no other process can execute a wait or signal on the same semaphore at the same time.
( Other processes could be allowed to do other things, including working with other
semaphores, they just can't have access to this semaphore. ) On single processors this can
be implemented by disabling interrupts during the execution of wait and signal;
Multiprocessor systems have to use more complex methods, including the use of
spinlocking.
One important problem that can arise when using semaphores to block processes waiting
for a limited resource is the problem of deadlocks, which occur when multiple processes
are blocked, each waiting for a resource that can only be freed by one of the other
( blocked ) processes, as illustrated in the following example. ( Deadlocks are covered
more completely in chapter 7. )
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
Another problem to consider is that of starvation, in which one or more processes gets
blocked forever, and never get a chance to take their turn in the critical section. For
example, in the semaphores above, we did not specify the algorithms for adding processes
to the waiting queue in the semaphore in the wait( ) call, or selecting one to be removed
from the queue in the signal( ) call. If the method chosen is a FIFO queue, then every
process will eventually get their turn, but if a LIFO queue is implemented instead, then the
first process to start waiting could starve.
Priority Inversion
Topic:7:7 Monitors
Monitors
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
Semaphores can be very useful for solving concurrency problems, but only if
programmers use them properly. If even one process fails to abide by the proper use of
semaphores, either accidentally or deliberately, then the whole system breaks down. (
And since concurrency problems are by definition rare events, the problem code may
easily go unnoticed and/or be heinous to debug. )
For this reason a higher-level language construct has been developed, called monitors.
A monitor is essentially a class, in which all data is private, and with the
special restriction that only one method within any given monitor object
may be active at the same time. An additional restriction is that monitor
methods may only access the shared data within the monitor and any data
passed to them as parameters. I.e. they cannot access any data external to
the monitor.
Figure 5.16 shows a schematic of a monitor, with an entry queue of processes waiting
their turn to execute monitor operations ( methods. )
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
In order to fully realize the potential of monitors, we need to introduce one additional new
data type, known as a condition.
o A variable of type condition has only two legal operations, wait and signal. I.e. if
X was defined as type condition, then legal operations would be X.wait( ) and
X.signal( )
o The wait operation blocks a process until some other process calls signal, and adds
the blocked process onto a list associated with that condition.
o The signal process does nothing if there are no processes waiting on that condition.
Otherwise it wakes up exactly one process from the condition's list of waiting
processes. ( Contrast this with counting semaphores, which always affect the
semaphore on a signal call. )
Figure 6.18 below illustrates a monitor that includes condition variables within its data
space. Note that the condition variables, along with the list of processes currently waiting
for the conditions, are in the data space of the monitor - The processes on these lists are
not "in" the monitor, in the sense that they are not executing any code in the monitor.
But now there is a potential problem - If process P within the monitor issues a signal that
would wake up process Q also within the monitor, then there would be two processes
running simultaneously within the monitor, violating the exclusion requirement.
Accordingly there are two possible solutions to this dilemma:
Java and C# ( C sharp ) offer monitors bulit-in to the language. Erlang offers similar but
different constructs.
Condition variables can be implemented using semaphores as well. For a condition x, a
semaphore "x_sem" and an integer "x_count" are introduced, both initialized to zero. The
wait and signal methods are then implemented as follows. ( This approach to the condition
implements the signal-and-wait option described above for ensuring that only one process
at a time is active inside the monitor. )
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
In monitors, wait
always block the In semaphore, wait does not always block the caller.
caller.
nearly identical - One can think of the producer as producing full buffers,
and the consumer producing empty buffers.
In the readers-writers problem there are some processes ( termed readers ) who only read
the shared data, and never change it, and there are other processes ( termed writers ) who
may change the data in addition to or instead of reading it. There is no limit to how many
readers can access the data simultaneously, but when a writer accesses the data, it needs
exclusive access.
There are several variations to the readers-writers problem, most centered around relative
priorities of readers versus writers.
o The first readers-writers problem gives priority to readers. In this problem, if a
reader wants access to the data, and there is not already a writer accessing it, then
access is granted to the reader. A solution to this problem can lead to starvation of
the writers, as there could always be more readers coming along to access the data.
( A steady stream of readers will jump ahead of waiting writers as long as there is
currently already another reader accessing the data, because the writer is forced to
wait until the data is idle, which may never happen if there are enough readers. )
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
o The second readers-writers problem gives priority to the writers. In this problem,
when a writer wants access to the data it jumps to the head of the queue - All
waiting readers are blocked, and the writer gets access to the data as soon as it
becomes available. In this solution the readers may be starved by a steady stream
of writers.
The following code is an example of the first readers-writers problem, and involves an
important counter and two binary semaphores:
o readcount is used by the reader processes, to count the number of readers currently
accessing the data.
o mutex is a semaphore used only by the readers for controlled access to readcount.
o rw_mutex is a semaphore used to block and release the writers. The first reader to
access the data will set this lock and the last reader to exit will release it; The
remaining readers do not touch rw_mutex. ( Eighth edition called this variable
wrt. )
o Note that the first reader to come along will block on rw_mutex if there is currently
a writer accessing the data, and that all following readers will only block on mutex
for their turn to increment readcount.
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
Some hardware implementations provide specific reader-writer locks, which are accessed
using an argument specifying whether access is requested for reading or writing. The use
of reader-writer locks is beneficial for situation in which: (1) processes can be easily
identified as either readers or writers, and (2) there are significantly more readers than
writers, making the additional overhead of the reader-writer lock pay off in terms of
increased concurrency of the readers.
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH
One possible solution, as shown in the following code section, is to use a set of five
semaphores ( chopsticks[ 5 ] ), and to have each hungry philosopher first wait on their left
chopstick ( chopsticks[ i ] ), and then wait on their right chopstick ( chopsticks[ ( i + 1 ) %
5])
But suppose that all five philosophers get hungry at the same time, and each starts by
picking up their left chopstick. They then look for their right chopstick, but because it is
unavailable, they wait for it, forever, and eventually all the philosophers starve due to the
resulting deadlock.
OPERATING SYSTEMS UNIT-II TEC /R20/3-1/2024-2025 CSE-AI/ML
KATIKAM MAHESH