Chapter 5, Process Synchronization

Ace your homework & exams now with Quizwiz!

Atomically

"One" uninterruptible unit

Solution to the Critical Section Problem

(1) Mutual Exclusion: If a process Pi is executing in its critical section, NO other process can be EXECUTING in their critical section (2) Progress: If no process is executing in its critical section and a process want to enter their critical section, ONLY those processes that are not executing in their remainder section can decide which will enter its critical section next. (3) Bounded Waiting: There exists a bound or limit, on the number of times, other processes are allowed to enter their critical section AFTER a process has made a request to enter its critical section before the request is granted. Structures in kernel can face race conditions for structures.

Reader-Writer Problems

(1) This requires that no reader be kept waiting unless A writer has obtained permission to use the shared object. No reader should wait for another reader to finish simply because a writer is waiting. (2) Once a WRITER is ready, that writer performs the write as soon as possible. If the writer is waiting to access the object, no new readers MAY start reading. The solution to this problem is that a mutex and wrt is initalized to 1, and readcount to 0. wrt is common to both the reader and the writer processes. The mutex semaphore is used to ensure mutual exclusion when readcount is updated. Readcount = variable that keeps track of HOW many processes are currently reading the object. Wrt = functions as a mutual exclusion semaphore for writers. It is used by the first or last reader that enters or exits the critical section. Another solution is that we have reader-writer locks. Acquiring a reader-writer lock requires specifying the MODE - read or write access. Read data = reader-writer lock in read mode Modify data = shared data in write mode. Multiple processes can acquire a reader-writer LOCK in read mode BUT only one process can acquire the lock for writing for exclusive access.

Cooperating Process

A cooperating process is a process that is affected by other processes executing in an system. (1) They share logical address spaces and shared data (2) Concurrent access may result in data inconsistency

When is a process deadlocked?

A process is deadlocked state when every process in the set is waiting for AN event caused by another process in the set (e.g. resource acquisition and release). Another problem is starvation.

Semaphore

A semaphore is an INTEGER variable is that accessed only through TWO standard atomic operations: wait() and signals() When one process modifies the semaphore value, NO other process can modify the same semaphore value AT the same time. In the case of wait(S), the testing of integer value of S and S-- MUST be executed without interruption. The wait() operation decreases the count, while the signal() operation increases the count

Race Condition

A situation where SEVERAL processes access and manipulate the SAME DATA at the same time, and the outcome of the execution DEPENDS on the particular order to access. To guard against race condition - we need to make sure 1 process can manipulate at a time (especially in a multicore system where several threads are sharing data)

Problems of Synchronization

Bounded-Buffer, Readers-Writers, Dining-Philosophers

Critical Section

Each process HAS a segment of code in which the process MAY be changing common variables, updating a table, and writing a file. A critical SECTION is a section in the program that needs to be protected from concurrent access. An IMPORTANT feature: When one process is executing in a critical section, NO other process is allowed TO execute in the critical section. No TWO processes are executing in their critical sections AT the same time. Each process MUST request permission to enter its critical section. The section of code implementing this request is the entry section. The critical section is followed by an exit section. The remaining code is the remainder section.

How do semaphores work?

Each process that wishes to use a resource - performs a wait() operation on the semaphore (decreases the count). When a process releases a resource, it performs a signal() operation to INCREMENT the count. When the COUNT for a semaphore is 0, all resources are used. Processes that wish to use a resource WILL block until the count becomes greater than 0. Semaphore solves 2 problems:

Semaphore Structure

Each semaphore has an integer value AND a list of processes called list. When a process must WAIT on a semaphore, it is added to the list of processe. A signal() operation REMOVES one process from the list of waiting processes, and awakens that process.

Preemptive Kernel

In a preemptive kernel, these kernels allow a process to be PRE-EMPTED while it is running in kernel mode. With preemptive kernel - they are designed so no race conditions occur. It is difficult to design for SMP architecture; since it's possible for two kernel-mode processes to run at the same time on different processors. Why? -All a real-time process to pre-empted a process is CURRENTLY running in the kernel -Kernel may be more responsive; less risk that a kernel mode process will run for a long time.

Synchronization in Linux

Linux kernel provides spinlocks and semaphores for locking in the kernel. -On SMP machine, spinlock is important so it is held for short durations -On single processor, we don't use spinlocks and they are replaced by enabling and disabling kernel preemption. We disable and enable them by doing the prempt_disable() and preempt_enable() calls. The kernel is not preemptible if a kernel mode task is holding a lock. Spinlocks are only used when a lock is held for a short duration. When a lock is held for a longer period, semaphores are appropriate.

Mutex Lock

Mutex = Mutual Exclusion. We use the mutex lock to protect critical regions and prevent RACE conditions. A process MUST acquire a lock before entering a critical section; it then releases a lock when it exits the critical section. The acquire() acquires the lock and the release() releases the lock. The mutex lock has a boolean variable, called available, whose value indicates if the lock is available or not. If the lock is available, a call to acquire() succeeds, otherwise unavailable. A process that attempts to acquire an unavailable lock IS blocked until the lock is released. Calls to acquire() and release() MUST be perfoermed automically. The main disadvantage of implemention is that it requires busy waiting. while a process is in its critical section, any other process that TRIES to enter its critical section MUST loop continuously in the call to acquire().

Synchronization Hardware

Peterson's solution may not work on a modern system architecture. A solution is a LOCK. Race conditions are prevented by requiring the critical region to be protected by locks. A process MUST acquire a lock before entering the critical section, then it releases the lock when it exits the critical section. It will acquire lock, goes into critical section, releases the lock, and in remainder section. Criticial section problem can be solved in a single processor because it prevents interrupts from occuring WHILE a shared variable is being modified; doing this will make sure that the set of instruction is executed and no instructions are run (nonpreemptive kernels). Disabling interrupts on a multiprocessor is time consuming and decreases effficiency. Most computer system provide special hardware instructions that let us test and modify the content of a word OR to swap the contents of two words automatically (in 1 uninterruptible unit).

Adaptive Mutex

Protects ACCESS to every critical data item. On multiprocessor system - it starts as a standard semaphore implemented as a spinlock If data is locked and in use, this can happen: 1. If the lock is held BY a thread currently running on the CPU, the thread spins while waiting for the lock to become available since it will FINISH soon. 2. If it is not in the run state, the thread blocks and goes to sleep, until it is awakened by the release of that lock. It is put to sleep so that it will not SPIN while waiting, since the lock will not be freed soon. On a SINGLE-processor system, threads always sleep rather than spin if they encounter a lock. Adaptive mutex is used to protect only data accessed by short code segments. If the code segment is longer, the thread will go back to sleep. Reader-writer locks are used to protect data accessed frequently but in a read-only manner.

Semaphore

Semaphore values may be negative; but they may never negative under the 'definition of semaphore' with busy waiting. If a semaphore is negative, ITS MAGNITUDE is the number of processes waiting on that semaphore. This fact results from 'switching' the order of the decrement and the test in the implementation of the wait() operation.

Turnstile

Solaris uses turnstiles to order the LIST of thread waiting to acquire an adaptive mutex OR a reader-writer lock. It is like a 'queue' structure that contains threads blocked on a lock. If a thread wants to acquire a lock that is being used, it will enter the turnstile for it. When the lock is released, the kernel selects a thread from the turnstile AS THE NEXT owner of the lock. Each synchronized object with AT least one thread blocked on the object's lock requires a separate turnstile. Turnstiles are organized by a priority inheritance protocol; if a lower-priority thread currently holds a lock on which a higher-priority thread is blocked, the thread with the lower priority will inherit the priority of the higher-priority thread.

CompareAndSwap()

The compare_and_swap is constrast to the testAndSet() operates on 3 operands. The operand value is set to the new value ONLY if the expression *value == exected is true. This is done atomically. Mutual exclusion is done as follows: a global variable(lock) is declared and set to 0. The FIRST process that invokes compareAndSwap() will set it lock to 1. It will ENTER its critical section, because the original value of lock was equal to the expected value of 0. Calls for compareAndSwap() will not succeed, because lock is now not equal to the value of 0. When a process exists its critical section, it SETS lock back to 0, which allows another process to enter its section. The ALGORITHMS satisfy mutual exclusion, BUT not the bounded waiting requirement.

Deadlock and Starvation

The implementation of a semaphore with a WAITING queue may result in a situation where two or more processes are waiting for an EVENT that can be caused by ONLY one of the waiting processes. The event is the EXECUTION of the signal operation. When a state is reached, the processes are deadlocked.

Implementation of semaphore

The main disadvantage of semaphore IS that is requires busy waiting; any other process MUST loop in the entry code while it is waiting. This wastes CPU cycles that could be used productively.

Monitor

The monitor is an ADT that presents a set of programmer defined operations that provide mutual exclusion in the monitor. The monitor construct ensures that 1 process at a time is active within the monitor.; there is no need to code synchronization.

Signal() Operation

The signal operation increases the semaphore value, and if the value is less than 0, we remove a process from the semaphore list, and wakeUP! The wakeup() resumes the execution of the blocked process P.

Counting Semaphore

The value of a counting semaphore CAN range over an unrestricted domain Counting semaphores can be used to CONTROL access to a given resource a 'finite' number of instances. The semaphore is initialized to the number of resources available.

Binary Semaphore

The value of it can range between 0 and 1 Binary semaphores on some systems CAN be known as mutex locks - since they are locks that provide mutual exclusion and DEAL with the critical section problem for multiple processes. The n processes share a semaphore, mutex, initalized to 1.

Wait() Operation

The wait() operation reduces the semaphore value and IF the value is less than 0, we add this process t othe list and block it. The block() suspends the process that invokes it.

Priority Inversion

There is a challenge when a higher priority needs to READ or modify kernel data accessed by a lower-priority process or chain of lower-priority processes. Since kernel data is PROTECTED with a lock, the higher-priority will have to wait for the lower-priority to finish with a resources. Priority inversion is WHEN a LOWER priority process has affected how long a higher priority process MUST wait for L to reliquinish a resource.

Why is important semaphores are executed atomically?

They must be executed atomically so that we can guarantee that NO two processes can execute wait() and signal() operations AT the same time on a semaphore (this is the critical section problem). On a single processor environment, we can solve it by not letting interrupts happen, only the currently running process executes UNTIL interrupts are reenabled, and the scheduler gains control. In a multiprocessor environment, interrupt MUST be disabled on every processor, OTHERWISE instructions from different processes may come in.

Priority Inheritance Protocol

This happens on a system with more than 2 priorities. This protocol solves the problem. All processes that are accessing a resource needed by a higher-priority process WILL inherit a higher priority UNTIL they are finished with the resource. When they are finished, their priorities GO BACK to the original values.

TestAndSet()

This instruction is executed atomically. If two TestAndSet() instructions are executed at the same time (on a different CPU), they will be executed sequentially in some order. If machine supports the instruction, we can implement mutual exclusion by declaring a variable, LOCK, initalized to false. ANOTHER SOLUTION: We have 2 variables, waiting[n] and lock. These data structures are set to false. To show that mutual exclusion is met, we note that a process Pi can ENTER its critical section ONLY if waiting[i] == false or key == false. The value of key can become false ONLY if test_and_set() is executed The first process to execute the testAndSet() will find key == false; all others must wait. The variable, waiting[i] CAN become false only if another process leaves its critical section; only one waiting[i] is set to false.

nonpreemptive kernel

This kernel does NOT allow a process running in kernel mode to be pre-empted - a kernel mode process will run until it exists in kernal mode, blocks, or yields control ON its own to the CPU. A nonpreemptive kernel is FREE from race conditions on kernel data structure AS only one process is active in the kernel at a time.

Spinlock

This type of mutex lock is a spinlock BECAUSE the process "spins" while waiting for the lock to become available (looping is a problem). One advantage of spinlock IS that no context switch is required since it takes time. Spinlocks are employed on multiprocessor systems where one thread can "spin" on one processor, WHILE another thread performs its critical section on another. It is useful BECAUSE locks are expected to be held for a short time. To overcome busy waiting - we can modify the wait() and signal() semaphore. If a process notices the wait() operation is NOT positive, THE PROCESS can block itself. -This places a process into a queue with the semaphore and the state of the process is switched to waiting. Control is given to the scheduler for another process. A process THAT is blocked, should be restarted when another process executes a signal() operation. It is RESTARTED by a wakeup() operation, which changes the process from waiting to ready. The process is placed into a ready queue.

Dispatcher Objects

Thread synchronize according to several mechanisms - such as mutux, semaphores, events, and timer. -Mutex is used to access data and release ownership -Timer are used to specify an amount of time has expired. Dispatchers may be in a signaled state (e.g. object is avaialble and thread will not block when trying to get the object) AND nonsignaled state (e.g object is not available and thread will be blocked) If the thread blocks on a nonsignaled object, it changes from ready to waiting and placed in a queue. If the state of dispatcher is moved to signaled, the kernel checks if any threads are WAITING on an object. If so, the kernel moves one or more threads from the waiting state to a ready state. Mutex locks can be used as a dispatcher object and thread states. If a thread is not able to get a lock, it will be placed in the waiting queue. When the mutex is signaled, the thread in front will acquire the lock.

Synchronization in Solaris

To control access to critical sections - Solaris provides an adaptive mutex, semaphores, turnstiles, and reader-writer locks

Bounded Buffer

To share memory between process, we use a BOUNDED buffer. The solution is that AT MOST buffer_size - 1 item in the buffer can be there at a time BUT - the value may not be the same (e.g. for a counter that is incremented when something is added, or removed). They may not be correctly executed concurrently because both processes can manipulate the counter at the same time.

How to handle critical sections in an OS

Two ways to handle critical section: preemptive kernels, nonpreemptive kernels.

Bounded Buffer Problem

We assume a pool consists of n buffers, which can hold an item. The mutex semaphore provides mutual exclusion for accesses to the buffer pool and is initalized to 1. The empty and full semaphores COUNT the number of empty and full buffers. Empty is initalized to n, and semaphore full is initalized to 0. The producer produces FULL buffers for the consumer OR the consumer produces empty buffers for the producer

When do we use reader-writer locks?

When there are more readers than writers.

Synchronization in Windows XP

Windows OS is a multithread kernel. When the (1) Windows kernel access a global resource on a uniprocessor system - it masks interrupts. (2) On a multiprocessor system, it protecrs access using spinlocks For thread synchronization outside of a kernel, Windows provides dispatcher objects.

Peterson's Solution

A solution to the critical-section problem by addressing the requirements. Restricted to 2 processes that ALTERNATE execution between their critical and remainder sections. The processes are numbered P0 and P1. When presenting Pi, we use Pj to denote the other process. j = 1 - i. Peterson's solution requires the two processes to SHARE two data items. The variable turn - indicates whose turn it is to enter the critical section. If turn = i, then processs Pi is allowed to execute in its critical section. The flag array is used to indicate if a PROCESS is ready to enter its critical section. If flag[i] = true, this value indicates that Pi is ready to enter the critical section. To enter a critical section, process Pi SETS the flag[i] = true, and then SETS turn to the value of j (if the other process wishes to enter the critical section, it can do do). If both processes try to enter at the same time, turn will be set to both i and j at the same time. Only one of these assignments will list. The eventual value of turn determines which of the two processes is allowed to enter the critical section first. To prove property 1: Pi ENTERS its critical section only if either flag[j] = false (j is not ready) OR turn == i. If both processes can be executing in their critical section at the same time, flag[0] == flag[1] = true = false. To prove property 2 and 3 - process Pi can be prevented from entering the critical section ONLY if it is stuck in the while loop with the condition, flag[j] = true and turn == j. This loop is the only one possible. If Pj is not READY to enter the critical section, then flag[j] = false, and Pi can enter the section. If Pj has set flag[j] to true, and is also executing in its while statement, then turn == i or turn == j. If turn == i, then Pi will enter the critical section. If turn == j, then Pj will enter the critical section. Once Pj exits its critical section, it will reset flag[j] to FALSE, allowing Pi to enter its critical section. If Pj resets flag[j] to true, it must also set turn to i. Since Pi does not change the value of the variable turn while in the while statement, Pi will enter the critical section after at most one entry by Pj.

Readers-Writers Problem

If a database is shared with concurrent processes - some may want to read, some may want to write If two readers SHARE data, there is no effect BUT if two writers ACCESS data, they may be issues. The SOLUTION is: writers have exclusive access to the shared database, while writing

Dining-Philosopher's Problem

Five philosophers are sharing a circular table surrounded by five. In the center of the table, there is a bowl of rice, and table is laid with five single chopsticks. When a philosopher thinks, she does not interact with colleagues. From time to time, a philosopher gets hungry and tries to pick up the two chopsticks closest to her. When a hungry philosopher has both chopsticks at the same time, she eats without releasing her chopsticks. Once done eating, she puts it down and thinks again. This problem represents concurrency control problems. The need to allocate several resources among several processes in a deadlock-free way and also starvation. A deadlock problem is created when all five philosophers ARE hungry. When each philosopher tries to grab their right chopstick, they are delayed forever. Solution to the deadlock problem -Allow at most four philosophers to be sitting at the SAME time at a table -Allow a philosopher to pick up her chopsticks ONLY if both chopsticks are available (SHE must pick this up at the critical section)


Related study sets

Palabras en catalán, euskera y gallego

View Set

Biology Exam on Chapter 23 and 29 - Friday March 10, 2017

View Set