Topics covered:
-
Concurrency: Address Spaces, Processes, Threads.
Difference between threads and processes.
Java threads and their operations: fork, join, sleep, interrupt..Address Spaces:
The range of virtual addresses that the operating system assigns to a user or separately running program is called an address space. This is the area of contiguous virtual addresses available for executing instructions and storing data.Kernel Mode
In Kernel mode, the executing code has complete and unrestricted access to the underlying hardware. It can execute any CPU instruction and reference any memory address. Kernel mode is generally reserved for the lowest-level, most trusted functions of the operating system. Crashes in kernel mode are catastrophic; they will halt the entire PC.User Mode
In User mode, the executing code has no ability to directly access hardware or reference memory. Code running in user mode must delegate to system APIs to access hardware or memory. Due to the protection afforded by this sort of isolation, crashes in user mode are always recoverable. Most of the code running on your computer will execute in user mode.-
Process Control Block
is a data structure in the operating system kernel containing the information needed to manage the scheduling of a particular process. The PCB is "the manifestation of a process in an operating system."
Program Counter
Program Counter (PC): A pointer to the address of the next instruction to be executed for this process.Context switch
Switching the CPU to another process requires saving the state of the old process and loading the saved state of the new process. This task is known as a context switch.Protected Instructions (Privileged Instructions)
Instructions available in kernel-mode, but not in user-mode, are called, naturally enough, privileged instructions.Stack Pointer
A stack pointer is a small register that stores the address of the last program request in a stack.-
Process status
Difference between threads and processes
A thread is a path of execution within a process. A process can contain multiple threads.
The primary difference is that threads within the same process run in a shared memory space, while processes run in separate memory spaces.
Threads are not independent of one another like processes are, and as a result threads share with other threads their code section, data section, and OS resources (like open files and signals). But, like process, a thread has its own program counter (PC), register set, and stack space.Describe the different states of a Thread and when do the state transitions occur.
The state of a Thread can be checked using the Thread.getState() method. Different states of a Thread are described in the Thread.State enum. They are:
NEW — a new Thread instance that was not yet started via Thread.start()
RUNNABLE — a running thread. It is called runnable because at any given time it could be either running or waiting for the next quantum of time from the thread scheduler. A NEW thread enters the RUNNABLE state when you call Thread.start() on it
BLOCKED — a running thread becomes blocked if it needs to enter a synchronized section but cannot do that due to another thread holding the monitor of this section
WAITING — a thread enters this state if it waits for another thread to perform a particular action. For instance, a thread enters this state upon calling the Object.wait() method on a monitor it holds, or the Thread.join() method on another thread
TIMED_WAITING — same as the above, but a thread enters this state after calling timed versions of Thread.sleep(), Object.wait(), Thread.join() and some other methods
TERMINATED — a thread has completed the execution of its Runnable.run() method and terminatedInterrupt
In system programming, an interrupt is a signal to the processor emitted by hardware or software indicating an event that needs immediate attention. An interrupt alerts the processor to a high-priority condition requiring the interruption of the current code the processor is executing. The processor responds by suspending its current activities, saving its state, and executing a function called an interrupt handler (or an interrupt service routine, ISR) to deal with the event. This interruption is temporary, and, after the interrupt handler finishes, the processor resumes normal activities.[1] There are two types of interrupts: hardware interrupts and software interrupts.
Hardware interrupts are used by devices to communicate that they require attention from the operating system.[2] Internally, hardware interrupts are implemented using electronic alerting signals that are sent to the processor from an external device, which is either a part of the computer itself, such as a disk controller, or an external peripheral. For example, pressing a key on the keyboard or moving the mouse triggers hardware interrupts that cause the processor to read the keystroke or mouse position. Unlike the software type (described below), hardware interrupts are asynchronous and can occur in the middle of instruction execution, requiring additional care in programming. The act of initiating a hardware interrupt is referred to as an interrupt request (IRQ).
A software interrupt is caused either by an exceptional condition in the processor itself, or a special instruction in the instruction set which causes an interrupt when it is executed. The former is often called a trap or exception and is used for errors or events occurring during program execution that are exceptional enough that they cannot be handled within the program itself. For example, a divide-by-zero exception will be thrown if the processor's arithmetic logic unit is commanded to divide a number by zero as this instruction is an error and impossible. The operating system will catch this exception, and can decide what to do about it: usually aborting the process and displaying an error message. Software interrupt instructions can function similarly to subroutine calls and are used for a variety of purposes, such as to request services from device drivers, like interrupts sent to and from a disk controller to request reading or writing of data to and from the disk.
-
Independent vs cooperating processes/threads: when to use which?
-
- Independent processes
Independent process is the process that can not affect or be affected by the other processes. Independent processes does not share any data like temporary or persistent with any other process.
- Independent processes
-
- Cooperating processes
Cooperating process is affect or be affected by the other processes executing in the system. Cooperating process shares data with other processes.
- Cooperating processes
-
Independent threads
- no shared state with other threads
- deterministic – input state determines result
- reproducible
- scheduling order doesn’t matter
-
cooperating threads – share state
- non-deterministic
- non-reproducible
Non-reproducibility and non-determinism means that bugs can be
intermittent. This makes debugging hard .
-
-
KEY CONCURRENCY TERMS
- critical section
A critical section is a piece of code that accesses a shared resource, usually a variable or data structure. - race condition
Outcome of thread execution depends on timing of threads - mutual exclusion
Ensuring that only one thread does a particular thing (e.g.: Go to the store and buy milk) at a time → one thread’s execution excludes the other - indeterminate
An indeterminate program consists of one or more race conditions; the output of the program varies from run to run, depending on which threads ran when. The outcome is thus not deterministic, something we usually expect from computer systems. - Lock
Construct that prevents someone from doing something
e.g.- Lock before entering critical section
- Unlock when leaving critical section
→ wait if locked
- Starvation
Occurs when 1 or more threads never gets access to critical section - Condition Variables
A condition variable is a synchronization object that enables a thread to efficiently wait for a change to shared state that is protected by a Lock.
- critical section
-
Implementing Mutual Exclusion
Hard to do with load/store, disable interrupts, why?
Instead, use hardware support: atomic read-modify-write instructions. How to implement lock using test-and-set instruction?-
Goal for solving critical sections:
-
Software ways to solve CS:
-
Why hard to do with load/store:
-
Hardware solutions to Synchronization
-
Atomic read-modify-write instructions
-
-
Disabling Interrupts
-
-
-
Test-and-Set (TS)
-
-
-
- Methodology for managing shared data:
Monitor abstraction extends the object oriented approach. Encapsulate shared data in an object.
Only access shared data using methods of the object. Treat methods as critical sections. Why locks are not enough an conditions variables are needed?
Example problems: Bounded buffer, Readers-Writers.-
Monitor Abstraction
-
Semaphores Abstraction
-
Why locks are not enough an conditions variables are needed?
-
Java default synchronization variables
Synchronization Problems and Solutions
- Multicore machines and locking
How does multicore caching work? Cache coherence protocol.
Impact of multicore caching on the performance of a lock implemented using Test-and-Set.
The contention problem.
The performance of naive Test-and-Set lock, vs TTAS lock, Exponential Backoff Lock, and Anderson Queue lock. What are the pro/cons of each of these lock implementations?-
A typical multiprocessor architecture
-
-
Cache coherence protocol
-
Exponential Backoff Lock
-
Anderson Queue Lock
- Deadlock definition of deadlock, conditions for its occurrence, approaches to preventing, avoiding, and detecting deadlock
-
Definition of deadlock
-
Conditions for its occurrence
-
-
Preventing
-
Avoidance
-
Detection