0% found this document useful (0 votes)
50 views116 pages

Unit 2-1

The document discusses processes and threads in operating systems. It defines processes and threads, and describes process states, context switching, scheduling queues, and operations like process creation and termination. It also covers topics like inter-process communication and process synchronization.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
50 views116 pages

Unit 2-1

The document discusses processes and threads in operating systems. It defines processes and threads, and describes process states, context switching, scheduling queues, and operations like process creation and termination. It also covers topics like inter-process communication and process synchronization.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 116

Unit 2 Process Management

Processes: Process Concept


Threads –
Process Scheduling –
Operations on Processes
Inter process Communication –
Communication in Client Server Systems-Pipes (RPC, Pipes) -
Process Synchronization: The Critical-Section Problem -
Semaphores Mutex Locks- Classic Problems of
Synchronization Monitors.
Case Study: Windows Threads and Linux Threads
Processes
• A process is basically a program in execution.
• we write our computer programs in a text file and when
we execute this program, it becomes a process which
performs all the tasks mentioned in the program.
• When a program is loaded into the memory and it
becomes a process, it can be divided into four sections
─ stack, heap, text and data.
Stack
• The process stack stores temporary information such as method or
function arguments, the return address, and local variables.
Heap
• This is the memory where a process is dynamically allotted while it is
running.
Data
• This section contains the global and static variables.
Text
• This consists of the information stored in the processor's registers as
well as the most recent activity indicated by the program counter's
value.
Process State
A process executes, it changes state
1. New. The process is being created.
2. Running. Instructions are being executed.
3. Waiting. The process is waiting for some event to occur (such as an
I/O completion or reception of a signal).
4. Ready. The process is waiting to be assigned to a processor.
5. Terminated. The process has finished execution.
Process Control Block
• Process Control Block (PCB) is a data structure used by the
operating system to store and manage all the information
related to a specific process.
Process State
• This specifies the process state i.e. new, ready, running,
waiting or terminated.
Process Number
• This shows the number of the particular process.
Program Counter
• This contains the address of the next instruction that
needs to be executed in the process.
Registers
• This specifies the registers that are used by the
process. They may include accumulators, index registers,
stack pointers, general purpose registers etc.
List of Open Files
• These are the different files that are associated with the
process
CPU Scheduling Information
• The process priority, pointers to scheduling queues etc. is the
CPU scheduling information that is contained in the PCB.
Memory Management Information
• 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.
I/O Status Information
• This information includes the list of I/O devices used by
the process, the list of files etc.
Accounting information
• Keeps track of the process's resource utilization data, such as CPU
time, memory usage, and I/O activities
Thread
• Thread is a lightweight process that the operating system can
schedule and run concurrently with other threads.
• operating system creates and manages threads, and they share the
same memory and resources as the program that created them.
• Example, in a browser, multiple tabs can be different threads.
Need for Thread
• Threads run in parallel improving the application performance.
• Threads can share common data.
• Priority can be assigned to the threads just like the process, and the
highest priority thread is scheduled first.
• Each thread has its own Thread Control Block (TCB). Like the process,
a context switch occurs for the thread, and register contents are
saved in (TCB).
Process Scheduling
• The process scheduling is the activity of the process manager that
handles the removal of the running process from the CPU and the
selection of another process on the basis of a particular strategy.
• For a single-processor system, there will never be more than one
running process. If there are more processes, the rest will have to wait
until the CPU is free and can be rescheduled.
Categories of Scheduling
1. Non-preemptive:
2. Preemptive
Non-preemptive:
• In non-preemptive, the resource can’t be taken from a process
until the process completes execution. The switching of
resources occurs when the running process terminates and
moves to a waiting state.
Preemptive:
• In preemptive scheduling, the OS allocates the resources to a
process for a fixed amount of time. During resource allocation,
the process switches from running state to ready state or from
waiting state to ready state. This switching occurs as the CPU
may give priority to other processes and replace the process
with higher priority with the running process.
Process Scheduling Queues
• All PCBs (Process control Blocks) are kept in Process Scheduling
Queues by the OS.
• A process’s PCB is unlinked from its present queue and then moved to
its next state queue when its status changes.
• Job queue – It contains all of the system’s processes.
• Ready queue – This queue maintains a list of all processes in
the main memory that are ready to run. This queue is always
filled with new processes.
• Device queue – The processes which are blocked due to
unavailability of an I/O device constitute this queue.
• Each rectangular box represents a queue. Two types of queues are present:
the ready queue and a set of device queues.
• The circles represent the resources that serve the queues, and the arrows
indicate the flow of processes in the system.
• A new process is initially put in the ready queue. It waits there until it is
selected for execution, or dispatched. Once the process is allocated the CPU
and is executing, one of several events could occur:
1. The process could issue an I/O request and then be placed in an I/O queue.
2. The process could create a new child process and wait for the child’s termination.
3. The process could be removed forcibly from the CPU, as a result of an interrupt,
and be put back in the ready queue.
Schedulers
• Schedulers are special system software which handle process
scheduling in various ways.
• decide which process to run
Types:
1. Long-Term Scheduler
2. Short-Term Scheduler
3. Medium-Term Scheduler
Long-Term Scheduler
• Long term scheduler is also known as job scheduler. It chooses the
processes from the pool (secondary memory) and keeps them in the
ready queue maintained in the primary memory.
• Long Term scheduler mainly controls the degree of
Multiprogramming. The purpose of long term scheduler is to choose a
perfect mix of IO bound and CPU bound processes among the jobs
present in the pool.
• If the job scheduler chooses more IO bound processes then all of the
jobs may reside in the blocked state all the time and the CPU will
remain idle most of the time. This will reduce the degree of
Multiprogramming.
Short term scheduler
• Short term scheduler is also known as CPU scheduler. It selects one of
the Jobs from the ready queue and dispatch to the CPU for the
execution.
• The Job of the short term scheduler can be very critical.
• if it selects job whose CPU burst time is very high then all the jobs,
starvation may occur.
Medium term scheduler
• Medium term scheduler takes care of the swapped out processes.
• If the running state processes needs some IO time for the completion
then there is a need to change its state from running to waiting.
• Medium term scheduler is used for this purpose. It removes the
process from the running state to make room for the other processes.
Such processes are the swapped out processes and this procedure is
called swapping.
Context Switch
• Context switching in an operating system involves saving the context or
state of a running process so that it can be restored later, and then loading
the context or state of another process and run it.(suspending the process
and then resuming it)
Example of Context Switching
• Suppose in the OS there (N) numbers of processes are stored in a Process
Control Block(PCB). The process is running using the CPU to do its job. While
a process is running, other processes with the highest priority queue up to
use the CPU to complete their job.
• Switching the CPU to another process requires performing a state save of
the current process and a state restore of a different process. This task is
known as a context switch
Operations on Processes
The operating system must provide a mechanism for process creation
and termination. The process can be created and deleted dynamically
by the operating system.
The Operations on the process includes
1. Process creation
2. Process Termination
Operations on Processes
Process Creation
• During Execution a process may create several new processes.
• The creating process is called as the parent process and the newly
created process is called as the child process.
• A process may be created by another process using fork().
• The operating systems identify the processes according to their
unique process identifier.
• The init process serves as the root parent process
for all the user process.
• Once the system has booted, the init process can
also create various user processes, such as a web
or print server, an ssh server.
• The kthreadd process is responsible for creating
additional processes that perform tasks on behalf
of the kernel.
• The sshd process is responsible for managing
clients that connect to the system by using
ssh(Secure shell)
• The login process is responsible for managing
clients that directly log onto the system. In this
example a client has logged on and is using the
bash shell, which has been assigned pid 8416
• The command ps –el will list complete information
for all processes currently active in the system.
When a process creates a new process, two possibilities for execution
exist:
1. The parent continues to execute concurrently with its children.
2. The parent waits until some or all of its children have terminated.
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 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
A parent may terminate the execution of one of its children for a variety of
reasons, such as
• The child has exceeded its usage of some of the resources that it has been
allocated.
• 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 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 is referred to as
cascading termination.
Example
/* exit with status 1 */
exit(1);
A parent process may wait for the termination of a child process by
using the wait() system call.
pid _t pid;
int status;
pid = wait(&status);

zombie process
A process that has terminated, but whose parent has not yet called
wait(), is known as a zombie process.
Inter process Communication
• Processes executing concurrently in the operating system may be either
independent processes or cooperating processes
Independent processes
• A process is independent if it cannot affect or be affected by the other
processes executing in the system.
• Any process that does not share data with any other process is
independent
Cooperating
• A process is cooperating if it can affect or be affected by the other
processes executing in the system.
Reasons for Interprocess Communication
1. Information sharing.
2. Computation speedup.
3. Modularity.
4. Convenience.
Reasons for Interprocess Communication
• Information sharing. Since several users may be interested in the same
piece of information (for instance, a shared file), we must provide an
environment to allow concurrent access to such information.
• Computation speedup. If we want a particular task to run faster, we
must break it into subtasks, each of which will be executing in parallel
with the others. Notice that such a speedup can be achieved only if the
computer has multiple processing cores.
• Modularity. We may want to construct the system in a modular
fashion, dividing the system functions into separate processes or
threads
• Convenience. Even an individual user may work on many tasks at the
same time. For instance, a user may be editing, listening to music, and
compiling in parallel.
Processes communication
• Processes can communicate with each other through
both:
1. Shared Memory
2. Message passing
Shared Memory- In the shared-memory model, a region of memory that
is shared by cooperating processes is established. Processes can then
exchange information by reading and writing data to the shared region.
Message passing- In the message-passing model, communication takes
place by means of messages exchanged between the cooperating
processes.
• send (message)
• received (message)
Shared-Memory Systems
• In the shared-memory model, a region of memory that is shared by
cooperating processes is established.
• Processes can then exchange information by reading and writing data
to the shared region.
• The processes are also responsible for ensuring that they are not
writing to the same location simultaneously.
Example producer–consumer problem,
• A producer process produces information that is consumed by a
consumer process.
• A web server produces (that is, provides) HTML files and images,
which are consumed (that is, read) by the client web browser
requesting the resource.
Buffer
• To allow producer and consumer processes to run concurrently, we
must have available a buffer of items that can be filled by the
producer and emptied by the consumer. This buffer will reside in a
region of memory that is shared by the producer and consumer
processes.
• A producer can produce one item while the consumer is consuming
another item. The producer and consumer must be synchronized, so
that the consumer does not try to consume an item that has not yet
been produced.
Buffer
• Two types of buffers can be used
1. unbounded buffer
2. bounded buffer

The unbounded buffer places no practical limit on the size of the buffer. The
producer can always produce new items.
The bounded buffer assumes a fixed buffer size. the producer must wait if the
buffer is full
• Count will be incremented when product is placed by producer in
buffer.
• Count will be decremented when product is consumed by consumer
from buffer.
Producer side
#define BUFFER SIZE 10 • In points to the next free position in
the buffer.
typedef struct • Out points to the first full position in
{ the buffer.
... • In==Out is full

}item;
item buffer[BUFFER SIZE];
int in = 0;
int out = 0;
Consumer side
item next consumed;
while (true)
{
while (in == out)
; /* do nothing */
next consumed = buffer[out];
out = (out + 1) % BUFFER SIZE;
/* consume the item in next consumed */
}
Message passing
In the message-passing model, communication takes place by means of
messages exchanged between the cooperating processes.
• send (message)
• received (message)
• If processes P and Q want to communicate, they must send messages
to and receive messages from each other: a communication link must
exist between them. This link can be implemented in a variety of
ways.
Several methods for logically implementing a link and the
send()/receive() operations:
1. •Direct or indirect communication(Naming)
2. •Synchronous or asynchronous communication(Synchronization)
3. •Automatic or explicit buffering

https://notesformsc.org/message-passing-system/
Direct Communication
In direct communication, processes must explicitly name the sender or
receiver in the communication.
The send() and receive() are defined as:
• send(P, message) - send a message to process P
• receive(Q, message) - receive a message from process Q
Indirect Communication
• In indirect communication, messages are sent and received from
mailboxes or ports. The processes can place messages into a mailbox
or remove messages from them. The mailbox has a unique
identification.
• send(M, message) - send a message to mailbox M
• receive(M, message) - recieve a message from mailbox M
Synchronous or asynchronous communication
• Message passing may be either blocking or nonblocking— also known
as synchronous and asynchronous.
1. Blocking send. The sending process is blocked until the message is
received by the receiving process or by the mailbox.
2. Nonblocking send. The sending process sends the message and
resumes operation.
3. Blocking receive. The receiver blocks until a message is available.
4. Nonblocking receive. The receiver retrieves either a valid message
or a null.
Automatic and Explicit Buffering
The messages exchanged between communicating processes resides in a
temporary queue. The queue can be implemented in three way:
1.Zero capacity – with zero capacity the link cannot have messages
waiting. Blocking send is the correct option.
2.Bounded capacity – the queue is of finite length n. If queue not full,
sender can continue to send messages. If full, blocking send.
3.Unbounded capacity – Infinite queue length; any number of
messages wait and sender never blocks.
Communication in Client –Server Systems
1. Sockets,
2. Remote procedure calls (RPCs),
3. Pipes
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.
• If a client on host X with IP address 146.86.5.20 with port
1625 wishes to establish a connection with a web server
(which is listening on port 80) at address 161.25.19.8. The
connection will consist of a pair of sockets:
(146.86.5.20:1625) on host X and (161.25.19.8:80) on the
web server.
Remote Procedure Calls
• Remote Procedure Call is a software communication
protocol that one program can use to request a service
from a program located in another computer on
a network without having to understand the network's
details.
Stub
• Acts as the representative of the remote procedure code.
• A separate stub exists for each separate remote procedure.
• When the client invokes a remote procedure, the RPC system
calls the appropriate stub, passing it the parameters provided
to the remote procedure.
• This stub locates the port on the server and marshals the
parameters. Parameter marshalling involves packaging the
parameters into a form that can be transmitted over a
network.
• The stub then transmits a message to the server using
message passing. A similar stub on the server side receives
this message and invokes the procedure on the server.
• First a client will sends RPC message to matchmaker
requesting the port address of the RPC it needs to execute.
• Matchmaker will find the port number and replies to the
client with port number.
• The port number is returned, and the RPC calls can be sent
to that port until the process terminates (or the server
crashes).
Pipes
• A pipe simply refers to a temporary software connection between two
processes.
• A pipe works on the first in, first out principle and behaves like a
queue data structure.
• With a pipe, the output of the first process becomes the input of the
second. However, the reverse does not happen. This is why a pipe is a
form of one-way communication between processes.
Two Types:
1. ordinary pipes
2. named pipe
1.Ordinary pipes
• Ordinary pipes allow two processes to communicate in standard
producer– consumer fashion.
• the producer writes to one end of the pipe (the write-end) and the
consumer reads from the other end (the read-end).
• As a result, ordinary pipes are unidirectional, allowing only one-way
communication.
• If two-way communication is required, two pipes must be used, with
each pipe sending data in a different direction.
• On UNIX systems, ordinary pipes are constructed using the function
pipe(int fd[])
• fd[0] is the read-end of the pipe, and fd[1] is the write-end
• An ordinary pipe cannot be accessed from outside the process that
created it. Typically, a parent process creates a pipe and uses it to
communicate with a child process that it creates via fork().
• The parent process creates a pipe and then sends a fork() call
creating the child process.
create the pipe Parent process and Writing(if (pid > 0))
if (pipe(fd) == -1) /* close the unused end of the pipe */
close(fd[READ END]);
{
/* write to the pipe */
fprintf(stderr,"Pipe failed");
write(fd[WRITE END], write msg, strlen(write msg));
return 1; /* close the write end of the pipe */
} close(fd[WRITE END]);
}
fork a child process Child process and Reading (else )
pid = fork(); /* close the unused end of the pipe */
close(fd[WRITE END]);
if (pid < 0) { /* error occurred */
/* read from the pipe */
fprintf(stderr, "Fork Failed");
read(fd[READ END], read msg, BUFFER SIZE);
return 1;
printf("read %s",read msg);
} /* close the Read end of the pipe */
close(fd[READ END]); }
2.Named Pipes
• Ordinary pipes provide a simple mechanism for allowing a pair of processes
to communicate.
• However, ordinary pipes exist only while the processes are communicating
with one another. once the processes have finished communicating and
have terminated, the ordinary pipe ceases to exist.
• Named pipes provide a much more powerful communication tool.
Communication can be bidirectional, and no parent–child relationship is
required. Once a named pipe is established, several processes can use it for
communication.
• Named pipes continue to exist after communicating processes have finished
• Named pipes, also known as FIFOs (First In, First Out), are a form of inter-
process communication.
Creating a Named Pipe:
• On UNIX systems, Names pipes are constructed using the function
mkfifo(my_pipe)

• Example
int main()
{
mkfifo("my_pipe", 0666);
return 0;
}
Writing :
int fd = open("my_pipe");
write(fd, "Hello, Pipe!", 13);
close(fd);
Reading:
int fd = open("my_pipe");
char buffer[256];
read(fd, buffer, sizeof(buffer));
close(fd);
Process Synchronization
• Process Synchronization is the task of coordinating the execution
of processes in a way that no two processes can have access to the
same shared data and resources.
• It is specially needed in a multi-process system when multiple
processes are running together, and more than one processes try to
gain access to the same shared resource or data at the same time.
• The main objective of process synchronization is to ensure that
multiple processes access shared resources without interfering with
each other and to prevent the possibility of inconsistent data due to
concurrent access.
• To achieve this, various synchronization techniques such as
semaphores, monitors, and critical sections are used.
Critical-Section Problem

• Each process has a segment of code, called a critical section,


in which the process may be changing common variables,
updating a table, writing a file, and so on.
• The important feature of the system is that, when one
process is executing in its critical section, no other process is
allowed to execute in its critical section.
• That is, no two processes are executing in their critical
sections at the same time.
• The critical-section problem is to design a protocol that the
processes can use to cooperate. Each process must request
permission to enter its critical section.
Solution to the critical-section
A solution to the critical-section problem must satisfy the following
three requirements
1.Mutual exclusion
2.Progress
3.Bounded Waiting
1.Mutual Exclusion
If one process is executing inside critical section then the other
process must not enter in the critical section.
2.Progress
• Progress means that if a process is not using the critical
section, then it should not stop any other process from
accessing it. In other words, any process can enter a critical
section if it is free.
3.Bounded Waiting
• Bounded waiting means that each process must have a
limited waiting time. It should not wait endlessly to access
the critical section.
Example For Semaphore

int x = 10;
// Process 1 // Process 2
int s = 10; int s = 10;
int u = 20; int u = 20;
x = s + u; x = s - u;

If Process 1 is alone executed, then the value of x is denoted as x = 30;


If Process 2 is alone executed, then the value of x is denoted as x = -10;
If both the processes occur at the same time, then the compiler would be in a
confusion to choose which variable value i.e. -10 or 30. This state faced by the
variable x is Data Inconsistency.
Semaphores
• Semaphores are integer variables that are used to solve
the critical section problem by using two operations,
• wait and signal that are used for process
synchronization.

• Wait()- Helps in controlling the entry of processes in CS. The


operation decrements the value of its argument as soon as a process
enters the critical section.
• Signal()- Helps control the process's exit after execution from CS.
Increment the value of its argument as soon as the execution is
finished.
definition of signal()
definition of wait()
signal(S)
wait(S)
{ {
S--; S++;
} }
Types of Semaphores
1. Binary Semaphore
2. Counting Semaphore
Binary Semaphore(Mutex lock)
• There are only two values of Semaphore in Binary Semaphore
Concept. The two values are 1 and 0.
• 0 represents that a process or a thread is in the critical section(i.e. it is
accessing the shared resource), while the other process or thread
should wait for it to complete.
• On the other hand, 1 means that no process is accessing the shared
resource, and the critical section is free
Counting Semaphore
• Counting semaphores can be used to control access to a given
resource consisting of a finite number of instances
• There are two sets of values of Semaphore in Counting Semaphore
Concept.
• The two types of values are values greater than and equal to one and
• other type is value equal to zero.
• If the Value of Binary Semaphore is greater than or equal to 1, then the
process has the capability to enter the critical section area.
• If the value of Binary Semaphore is 0 then the process does not have
the capability to enter the critical section area.
Mutex
• Mutex is a specific kind of binary semaphore that is used to provide a
locking mechanism.
• It stands for Mutual Exclusion Object.
• The mutex locking mechanism ensures only one thread can acquire
the mutex and enter the critical section. This thread only releases the
mutex when it exits in the critical section.
Example
wait (mutex);
.....
Critical Section
.....
signal (mutex);
Use of Mutex
• A mutex provides mutual exclusion, either producer or consumer who
can have the key (mutex) and proceed with their work. As long as the
producer fills the buffer, the user needs to wait, and vice versa. In
Mutex lock, all the time, only a single thread can work with the entire
buffer.
Producer-Consumer

Classic Problems of Synchronization


• Bounded-Buffer Problem(Producer-Consumer)
• Readers –Writers Problem
• Dining-Philosophers Problem
Bounded-Buffer Problem(Producer-Consumer)

• Producer in the producer-consumer problem, Producer is producing


some items, whereas there is one Consumer that is consuming the
items produced by the Producer. The same memory buffer is shared
by both producers and consumers which is of fixed-size.

• The task of the Producer is to produce the item, put it into the
memory buffer, and again start producing items. Whereas the task of
the Consumer is to consume the item from the memory buffer.
• The producer should produce data only when the buffer is not full. In
case it is found that the buffer is full, the producer is not allowed to
store any data into the memory buffer.
• Data can only be consumed by the consumer if and only if the memory
buffer is not empty. In case it is found that the buffer is empty, the
consumer is not allowed to use any data from the memory buffer.
• Accessing memory buffer should not be allowed to producer and
consumer at the same time.
• Count will be incremented when product is placed by producer in
buffer.
• Count will be decremented when product is consumed by consumer
from buffer.
Accessing memory buffer should not be allowed to producer and
consumer at the same time.
• To solve this problem, we need two counting semaphores – Full and
Empty.
• “Full” keeps track of number of items in the buffer at any given time
• “Empty” keeps track of number of unoccupied slots.
• When producer produces an item
then the value of “empty” is
Solution for Producer reduced by 1 because one slot will
Do be filled now.
• The value of mutex is also reduced
{ to prevent consumer to access the
//produce an item buffer.
wait(empty); • Now, the producer has placed the
wait(mutex); item and thus the value of “full” is
//place in buffer increased by 1.
signal(mutex); • The value of mutex is also
signal(full); increased by 1 because the task of
producer has been completed and
}while(true) consumer can access the buffer.
• As the consumer is removing an
item from buffer, therefore the
Solution for Consumer
value of “full” is reduced by 1
Do • the value is mutex is also
{ reduced so that the producer
cannot access the buffer at this
wait(full); moment.
wait(mutex); • Now, the consumer has
// consume item from buffer consumed the item, thus
increasing the value of “empty”
signal(mutex); by 1.
signal(empty); • The value of mutex is also
}while(true) increased so that producer can
access the buffer now
Readers –Writers Problem
• Suppose that a database is to be shared among several concurrent
processes.
• Some of these processes may want only to read the database,
whereas others may want to update (that is, to read and write) the
database.
• We distinguish between these two types of processes by referring to
the former as readers and to the latter as writers.
• If two readers access the shared data simultaneously, no adverse
effects will result.
• However, if a writer and some other process (either a reader or a
writer) access the database simultaneously, confusion may occur.
• To ensure that these difficulties do not arise, we require that the
writers have exclusive access to the shared database while writing to
the database.
• This synchronization problem is referred to as the readers–writers
problem.
Conditions for reader and writers problem
• No reader be kept waiting unless a writer has already obtained
permission to use the shared object.
• Once a writer is ready, that writer perform its write as soon as
possible.
Solution to the first readers–writers problem
The reader processes share the following data structures:
semaphore rw_mutex = 1;
semaphore mutex = 1;
int read count = 0;
• The semaphores mutex and rw mutex are initialized to 1;
• read count is initialized to 0.
• The semaphore rw_mutex is common to both reader and writer
process.
• The read count variable keeps track of how many processes are
currently reading the object
structure of a writer process
do
{
wait(rw_mutex); ...
/* writing is performed */ ...
signal(rw_mutex);
} while (true);
Structure of a reader process
do {
wait(mutex);
read count++;
if (read count == 1)
wait(rw_mutex);
signal(mutex);
...
/* reading is performed */
...
wait(mutex);
read count--;
if (read count == 0)
signal(rw_mutex);
signal(mutex);
• Acquiring a reader–writer lock requires specifying the mode of the
lock: either read or write access.
• When a process wishes only to read shared data, it requests the
reader–writer lock in read mode.
• A process wishing to modify the shared data must request the lock in
write mode.
• Multiple processes are permitted to concurrently acquire a reader–
writer lock in read mode, but only one process may acquire the lock
for writing, as exclusive access is required for writers.
Dining-Philosophers Problem
• Consider five philosophers who spend their lives thinking and eating. The
philosophers share a circular table surrounded by five chairs, each
belonging to one philosopher. In the center of the table is a bowl of rice,
and the table is laid with five single chopsticks
• When a philosopher thinks, she does not interact with her colleagues.
• From time to time, a philosopher gets hungry and tries to pick up the two
chopsticks that are closest to her (the chopsticks that are between her and
her left and right neighbors).
• A philosopher may pick up only one chopstick at a time. Obviously, she
cannot pick up a chopstick that is already in the hand of a neighbor.
• When a hungry philosopher has both her chopsticks at the same time, she
eats without releasing the chopsticks. When she is finished eating, she puts
down both chopsticks and starts thinking again.
• It is a simple representation of the need to allocate several resources
among several processes in a deadlock-free and starvation-free
manner.
• One simple solution is to represent each chopstick with a semaphore.
• A philosopher tries to grab a chopstick by executing a wait() operation
on that semaphore.
• She releases her chopsticks by executing the signal() operation on the
appropriate semaphores.
semaphore chopstick[5];
do {
wait(chopstick[i]); \\left
wait(chopstick[(i+1) % 5]); \\right
...
/* eat for awhile */
...
signal(chopstick[i]);
signal(chopstick[(i+1) % 5]);
...
/* think for awhile */
...
} while (true);
Wait Operation:
• wait(chopstick[i]): Philosopher i attempts to acquire the semaphore
for the chopstick on their left.
• wait(chopstick[(i+1) % 5]): Philosopher i attempts to acquire the
semaphore for the chopstick on their right. The modulo operation (%
5) is used to ensure that the index stays within the valid range (0 to 4).
Several possible remedies to the deadlock problem are replaced by:
1. Allow at most four philosophers to be sitting simultaneously at the
table.
2. Allow a philosopher to pick up her chopsticks only if both chopsticks
are available (to do this, she must pick them up in a critical section).
3. Use an asymmetric solution—that is, an odd-numbered philosopher
picks up first her left chopstick and then her right chopstick,
whereas an even numbered philosopher picks up her right
chopstick and then her left chopstick.
Monitors
• Although semaphores provide a convenient and effective
mechanism for process synchronization, using them
incorrectly can result in timing errors that are difficult to
detect, since these errors happen only if particular execution
sequences take place and these sequences do not always
occur.
Suppose that a process interchanges the order in which the wait() and signal()
operations on the semaphore mutex are executed, resulting in the following
execution:
signal(mutex);
...
critical section
...
wait(mutex);
In this situation, several processes may be executing in their critical sections
simultaneously, violating the mutual-exclusion requirement
Suppose that a process replaces signal(mutex) with wait(mutex). That
is, it executes
wait(mutex);
...
critical section
...
wait(mutex);
In this case, a deadlock will occur
• To deal with such errors, researchers have developed high-level
language constructs. – monitor
• An abstract data type—or ADT—encapsulates data with a set of
functions to operate on that data that are independent of any specific
implementation of the ADT.
• A monitor type is an ADT that includes a set of programmer defined
operations that are provided with mutual exclusion within the
monitor.
• A monitor type also contains declaration of variables, along with the
functions that operates on those variable.
• A function defined within a monitor can access only those variables
declared locally within the monitor and its formal parameters.
Similarly, the local variables of a monitor can be accessed by only the
local functions.
• The monitor construct ensures that only one process at a time is
active within the monitor.
monitor monitor name
{
/* shared variable declarations */ function Pn(...) {
function P1(...) { ...
... }
} initialization code (...) {
function P2(...) { ...
... }
} }
Condition Construct:
condition x, y(condition variable)
• The only operations that can be invoked on a condition variable are wait()
and signal()

• x.wait()-means that the process invoking this operation is suspended until


another process invokes x.signal()
• x.signal()-operation resumes exactly one suspended process.

• x.signal() operation is invoked by a process P, there exists a suspended


process Q associated with condition x. Clearly, if the suspended process Q is
allowed to resume its execution, the signaling process P must wait.
Otherwise, both P and Q would be active simultaneously within the monitor.
The process use the Shared data with the help of monitor. This much better than
semaphores.
Case Study: Windows Threads and Linux Threads

• Imagine a software development team is working on a multi-threaded


application that needs to run on both Windows and Linux platforms.
Windows Threads:
Thread Creation:
Windows threads are created using the CreateThread function.
Each thread has its own set of registers, stack, and a thread-local storage area.
Thread Synchronization:
Windows provides various synchronization primitives like mutexes, semaphores, and events.
Critical sections can be used for lightweight synchronization within a process.
Thread Termination:
Threads can be terminated using the ExitThread function.
Thread termination can be abrupt, potentially leading to resource leaks if not handled properly.
Thread Priority:
Threads can be assigned priorities to control their execution order.
Priority reversal can occur when a low-priority thread holds a resource needed by a high-priority
thread.
Thread Local Storage:
Windows supports thread-local storage for data that is unique to each thread.
Linux Threads:
Thread Creation:
Threads in Linux are created using the clone system call, and they share the same memory space.
The pthread_create library function simplifies thread creation.
Thread Synchronization:
POSIX threads (pthreads) provide synchronization mechanisms such as mutexes, condition
variables, and barriers.
Thread Termination:
Threads can be terminated using pthread_exit.
Thread termination involves cleaning up resources, and it allows for a more controlled shutdown.
Thread Priority:
Linux supports thread priorities, but the implementation may vary between different distributions.
The Completely Fair Scheduler (CFS) is commonly used for thread scheduling.
Thread Local Storage:
Linux supports thread-local storage using the’ __thread’ keyword.
Thread-local storage is useful for data that should be private to each thread.

You might also like