Threads
In operating systems, a thread is the smallest sequence of programmed instructions that can be managed independently by a scheduler. A process can contain multiple threads, each executing a different task concurrently within the same process. Think of a process as a house, and threads as individuals living in that house. Each individual can do different things (like cooking, reading, or watching TV) simultaneously, but they all share the same resources of the house (like the kitchen, living room, and utilities). This is different from multiple processes, which are like separate houses, each with its own independent resources.
Why Use Threads?
Threads offer several advantages:
- Responsiveness: In interactive applications, threads allow a program to remain responsive to user input even while performing long-running operations in the background. For example, a word processor can allow you to continue typing while it is saving your document.
- Resource Sharing: Threads within the same process share the same memory space and resources, such as code, data, and open files. This makes communication and data sharing between threads much easier and more efficient than inter-process communication.
- Economy: Creating and switching between threads is generally faster and consumes fewer resources than creating and switching between processes. This is because threads share the process's context, so less information needs to be saved and restored during a context switch.
- Scalability: On multi-processor or multi-core systems, threads can be run in parallel on different processors, significantly improving performance and throughput.
Thread Models
There are three common models for implementing threads, which describe how user-level threads (ULTs) and kernel-level threads (KLTs) are mapped to each other:
1. Many-to-One Model
In this model, many user threads are mapped to a single kernel thread. The operating system is unaware of the user threads. Thread management (creation, scheduling, synchronization) is handled entirely by a user-level threads library.
- Pros: Fast thread switching, efficient.
- Cons: If one user thread makes a blocking system call, the entire process (and all its threads) blocks, as the kernel is unaware of other user threads. Cannot take advantage of multiple processors, as only one user thread can run at a time on a single CPU.
2. One-to-One Model
In this model, each user thread is mapped to a separate kernel thread. The operating system directly supports and manages user threads.
- Pros: Allows other threads in the process to continue running when one thread makes a blocking system call. Can take advantage of multiple processors by scheduling different threads on different CPUs.
- Cons: Creating a user thread requires creating a corresponding kernel thread, which is more expensive and can limit the number of threads a system can support.
3. Many-to-Many Model
This model multiplexes many user threads to a smaller or equal number of kernel threads. The number of kernel threads can be fixed or dynamic.
- Pros: Combines the benefits of both Many-to-One and One-to-One models. Allows for parallelism on multiple processors while managing the overhead of kernel threads.
- Cons: More complex to implement and manage.
Thread Implementation
Threads can be implemented in two ways:
User Threads
User threads are managed entirely in user space without the kernel's knowledge. A threads library provides an API for creating and managing threads. Examples include POSIX Threads (pthreads) and Java threads.
Kernel Threads
Kernel threads are directly supported and managed by the operating system kernel. The kernel is responsible for creating, scheduling, and managing kernel threads. Most modern operating systems (like Windows, Linux, macOS) support kernel threads.
Thread Synchronization
When multiple threads share data, there's a risk of race conditions, where the outcome depends on the unpredictable timing of thread execution. To prevent this, synchronization mechanisms are used to ensure that only one thread can access a shared resource at a time. Common mechanisms include:
- Mutexes (Mutual Exclusion Locks): A mutex is a locking mechanism that grants exclusive access to a resource. A thread must acquire the mutex before accessing the resource and release it afterward. If another thread tries to acquire a locked mutex, it will block until the mutex is released.
- Semaphores: A semaphore is a signaling mechanism. It's an integer variable that is accessed only through two atomic operations: `wait()` (decrement) and `signal()` (increment). Semaphores can be used to control access to a pool of resources or to signal between threads.
- Monitors: A monitor is a higher-level synchronization construct that encapsulates shared data and the procedures that operate on it, along with mutual exclusion. It ensures that only one thread can be active within the monitor at any given time.
- Many-To-One: Many U's (User) to One K (Kernel). Like many students (U) in one classroom (K).
- One-to-One: One U to One K. Like one student (U) per tutor (K).
- Many-to-Many: Many U's to Many K's. Like many students (U) with many tutors (K).
CPU Scheduling Algorithms
CPU scheduling is the process of selecting which process or thread from the ready queue will be allocated to the CPU next. The goal is to maximize CPU utilization, throughput, and minimize response time, waiting time, and turnaround time.
Scheduling Criteria
- CPU Utilization: Keep the CPU as busy as possible.
- Throughput: Number of processes completed per unit of time.
- Turnaround Time: The interval from the time of submission of a process to its completion. (Completion Time - Arrival Time)
- Waiting Time: The total time spent by the process waiting in the ready queue. (Turnaround Time - Burst Time)
- Response Time: The time from the submission of a request until the first response is produced. (First Response Time - Arrival Time)
Types of CPU Scheduling
- Non-preemptive: Once a process is allocated the CPU, it keeps the CPU until it voluntarily releases it (e.g., by terminating or switching to the waiting state).
- Preemptive: Allows a process to be interrupted and moved to the ready queue by the operating system. This is useful for time-sharing systems.
Common CPU Scheduling Algorithms
1. First-Come, First-Served (FCFS)
Processes are served in the order they arrive in the ready queue. It is a non-preemptive algorithm.
Example: Processes P1, P2, P3 arrive with burst times 24, 3, 1 respectively. Order of execution: P1, P2, P3. P1: 0-24 (Waiting Time = 0) P2: 24-27 (Waiting Time = 24) P3: 27-28 (Waiting Time = 27) Average Waiting Time = (0 + 24 + 27) / 3 = 17.
- Pros: Simple to understand and implement.
- Cons: Suffers from the "convoy effect" where a long process at the front of the queue can make short processes behind it wait for a long time, leading to high average waiting time.
2. Shortest-Job-Next (SJN) / Shortest-Process-Next (SPN)
The process with the smallest estimated next CPU burst time is selected to run next. It can be preemptive or non-preemptive.
- Non-preemptive SJN: Once a process starts, it runs to completion.
- Preemptive SJN (Shortest Remaining Time First - SRTF): If a new process arrives with a CPU burst length less than the remaining time of the current executing process, the current process is preempted.
Example (Non-preemptive SJN): Processes P1, P2, P3 arrive at time 0 with burst times 6, 8, 7. Order of execution: P1, P3, P2. P1: 0-6 (WT=0) P3: 6-13 (WT=6) P2: 13-21 (WT=13) Average WT = (0+13+6)/3 = 6.33
Example (SRTF): Processes P1, P2, P3 arrive at times 0, 2, 4 with burst times 8, 4, 9. Time 0: P1 arrives (BT=8). CPU allocated to P1. Time 2: P2 arrives (BT=4). P1 remaining BT = 6. P2's BT (4) < P1's remaining BT (6). Preempt P1, allocate to P2. Time 4: P3 arrives (BT=9). P2 remaining BT = 2. P2's remaining BT (2) < P3's BT (9). Continue P2. Time 6: P2 finishes. P1 remaining BT = 6. P3 BT = 9. P1's remaining BT (6) < P3's BT (9). Allocate to P1. Time 12: P1 finishes. P3 BT = 9. Allocate to P3. Time 21: P3 finishes. Turnaround Times: P1=12, P2=6, P3=15. Waiting Times: P1=4, P2=2, P3=6. Avg WT = (4+2+6)/3 = 4.
- Pros: Provably optimal in minimizing average waiting time.
- Cons: Difficult to estimate the next CPU burst time accurately. Can lead to starvation if short jobs keep arriving.
3. Priority Scheduling
Each process is assigned a priority, and the CPU is allocated to the process with the highest priority. Priorities can be assigned internally (e.g., based on job characteristics) or externally (e.g., based on importance). It can be preemptive or non-preemptive.
- Preemptive Priority: If a higher-priority process arrives, it preempts the currently running lower-priority process.
- Non-preemptive Priority: The currently running process continues until it completes or blocks, even if a higher-priority process arrives.
Problem: Starvation. Lower-priority processes may never get to execute if there is a continuous stream of higher-priority processes.
Solution: Aging. Gradually increase the priority of processes that have been waiting in the system for a long time.
Example (Preemptive Priority): Processes P1, P2, P3 arrive at times 0, 1, 2 with burst times 5, 3, 2 and priorities 2, 1, 3 (lower number means higher priority). Time 0: P1 arrives (BT=5, P=2). CPU allocated to P1. Time 1: P2 arrives (BT=3, P=1). P2's priority (1) is higher than P1's (2). Preempt P1, allocate to P2. P1 remaining BT = 4. Time 2: P3 arrives (BT=2, P=3). P2's priority (1) is still highest. Continue P2. Time 4: P2 finishes. P1 remaining BT = 4, P=2. P3 BT = 2, P=3. P1 has higher priority. Allocate to P1. Time 8: P1 finishes. P3 BT = 2, P=3. Allocate to P3. Time 10: P3 finishes. Turnaround Times: P1=8, P2=4, P3=8. Waiting Times: P1=3, P2=1, P3=6. Avg WT = (3+1+6)/3 = 3.33.
- Pros: Important processes can be given preference.
- Cons: Potential for starvation of low-priority processes.
4. Round Robin (RR)
Designed for time-sharing systems. It is a preemptive algorithm. Each process gets a small unit of CPU time called a time quantum or time slice. After the time quantum expires, the process is preempted and added to the end of the ready queue.
Key Factor: Time Quantum (q).
- If q is too large, RR behaves like FCFS.
- If q is too small, overhead from context switching becomes high.
Example: Processes P1, P2, P3 arrive at time 0 with burst times 24, 3, 3. Time Quantum q = 4. P1 runs for 4 units (0-4). Remaining BT=20. P1 goes to end of queue. Queue: [P2, P3, P1] P2 runs for 3 units (4-7). Remaining BT=0. P2 finishes. Queue: [P3, P1] P3 runs for 3 units (7-10). Remaining BT=0. P3 finishes. Queue: [P1] P1 runs for 4 units (10-14). Remaining BT=16. P1 goes to end of queue. Queue: [P1] P1 runs for 4 units (14-18). Remaining BT=12. P1 goes to end of queue. Queue: [P1] P1 runs for 4 units (18-22). Remaining BT=8. P1 goes to end of queue. Queue: [P1] P1 runs for 4 units (22-26). Remaining BT=4. P1 goes to end of queue. Queue: [P1] P1 runs for 4 units (26-30). Remaining BT=0. P1 finishes. Turnaround Times: P1=30, P2=7, P3=10. Waiting Times: P1=6, P2=4, P3=7. Avg WT = (6+4+7)/3 = 5.67.
- Pros: Fair, provides good response time for interactive users.
- Cons: Performance heavily depends on the time quantum. High context switching overhead if q is too small.
5. Multilevel Queue Scheduling
The ready queue is partitioned into several separate queues, each with its own scheduling algorithm. Processes are permanently assigned to a queue, usually based on some property of the process (e.g., memory size, priority, type of job).
- Scheduling between queues: Typically implemented as a fixed-priority preemptive scheduling. For example, foreground queue (interactive) might have RR, and background queue (batch) might have FCFS. If the foreground queue is empty, the background queue is scheduled.
6. Multilevel Feedback Queue Scheduling
Allows a process to move between queues. The idea is to separate processes based on their CPU burst characteristics. For example, a process that uses too much CPU time might be moved to a lower-priority queue. Processes that wait too long in a lower-priority queue might be moved to a higher-priority queue (aging). This is the most flexible algorithm and can be configured to give different properties to various combinations of processes.
Deadlock Characterization and Handling
A deadlock is a situation where two or more processes are blocked indefinitely, each waiting for a resource that is held by another process in the set.
Conditions for Deadlock (Coffman Conditions)
For a deadlock to occur, all four of the following conditions must hold simultaneously:
- Mutual Exclusion: At least one resource must be held in a non-sharable mode; that is, only one process can use the resource at any time. If another process requests the resource, the requesting process must wait until the resource has been released.
- Hold and Wait: A process must be holding at least one resource and waiting to acquire additional resources that are currently being held by other processes.
- No Preemption: Resources cannot be preempted; that is, a resource can be released only voluntarily by the process holding it, after that process has completed its task.
- Circular Wait: A set of waiting processes {P0, P1, ..., Pn} must exist such that P0 is waiting for a resource held by P1, P1 is waiting for a resource held by P2, ..., Pn-1 is waiting for a resource held by Pn, and Pn is waiting for a resource held by P0.
- Mutual Exclusion
- No Preemption
- Hold and Wait
- Circular Wait
Methods for Handling Deadlocks
There are four main approaches to handling deadlocks:
-
Deadlock Prevention: Ensure that at least one of the four Coffman conditions cannot hold.
- Preventing Mutual Exclusion: Not always possible, especially for non-sharable resources. Some systems may allow read-only sharing to avoid this.
-
Preventing Hold and Wait:
- Require all processes to request all their resources before they begin execution. This can lead to low resource utilization.
- Allow a process to request resources only when it is holding no resources. If it cannot get all requested resources, it must release all currently held resources. This can lead to starvation.
- Preventing No Preemption: If a process holding resources requests another resource that cannot be immediately allocated to it, then all resources that the process is currently holding must be preempted. This is complex to implement.
- Preventing Circular Wait: Impose a total ordering of all resource types and require that processes request resources in increasing order of enumeration. For example, if resource type R_i is numbered before R_j, then a process can request an instance of R_j only if it is not holding any instance of R_i.
-
Deadlock Avoidance: Dynamically analyze resource allocation states to ensure that the system never enters an unsafe state (a state from which a deadlock could occur).
-
Banker's Algorithm: This algorithm requires that each process declare the maximum number of resources of each type that it may request. The system keeps track of the currently allocated resources and the maximum demand of each process. Before granting a resource request, the system checks if granting the request would leave the system in a safe state. If it would, the request is granted; otherwise, the process must wait.
- Safe State: A state where there exists a sequence of all processes in the system such that for each process Pi, the resources that can be allocated to Pi do not exceed the currently available resources plus the resources held by all processes Pj, Pk, ... preceding Pi in the sequence.
- Unsafe State: A state that is not safe. An unsafe state may or may not lead to a deadlock.
- Resource-Allocation Graph (RAG) with cycles: A cycle in the RAG is a necessary condition for deadlock. For single instance resources, a cycle is also a sufficient condition. If there are multiple instances of a resource type, a cycle is not sufficient. An extension called the Wait-For Graph (WFG) is used.
-
Banker's Algorithm: This algorithm requires that each process declare the maximum number of resources of each type that it may request. The system keeps track of the currently allocated resources and the maximum demand of each process. Before granting a resource request, the system checks if granting the request would leave the system in a safe state. If it would, the request is granted; otherwise, the process must wait.
-
Deadlock Detection: Allow deadlocks to occur, then detect them and recover.
- The system periodically runs a deadlock detection algorithm. This algorithm typically involves finding cycles in the resource-allocation graph.
- If a cycle is found, a deadlock exists.
-
Deadlock Recovery: Once a deadlock is detected, the system must break the deadlock.
-
Process Termination:
- Abort one process at a time: Continue aborting processes until the deadlock is broken. Select a process to abort based on factors like priority, progress made, resources used, etc.
- Abort all processes involved in the deadlock: Simpler but more costly.
-
Resource Preemption:
- Select a victim resource to preempt and its process.
- Roll back the process to a previous state before it acquired the resource. This requires a restart point or checkpointing.
- Must avoid starvation (e.g., ensure that a process is not selected for rollback more than once).
-
Process Termination:
- Prevention: Make it impossible for deadlock conditions to occur. (Difficult in practice)
- Avoidance: Ensure the system stays in a "safe state". (Requires prior knowledge of resource needs)
- Detection & Recovery: Let it happen, then fix it. (Most practical for general systems)
Memory Management
Memory management is the process of controlling and coordinating computer memory, assigning blocks of memory to various running programs to optimize overall system performance. It involves allocating memory to processes when they need it and reclaiming it when they are done, while ensuring that processes do not interfere with each other's memory space.
Logical vs. Physical Address Space
Logical Address: An address generated by the CPU. It is also referred to as a virtual address.
Physical Address: An address that is actually present in the main memory hardware.
The mapping from logical to physical addresses is done by the Memory Management Unit (MMU), a hardware component.
Paging
Paging is a memory management scheme that supports non-contiguous allocation of physical memory. It solves the problem of external fragmentation.
- Pages: The logical address space is divided into fixed-size blocks called pages.
- Frames: The physical memory is divided into fixed-size blocks of the same size as pages, called frames.
- Page Table: For each process, a page table is maintained by the operating system. This table maps logical pages to physical frames. Each entry in the page table contains the frame number corresponding to the page.
-
Logical Address Structure: A logical address is divided into two parts:
- Page Number (p): Used as an index into the page table.
- Page Offset (d): The offset within the page (or frame).
- Page Fault: If a requested page is not currently in memory (i.e., its corresponding frame is not allocated or the page table entry indicates it's not present), a page fault trap is generated. The OS then handles this by finding a free frame, loading the required page from secondary storage into the frame, updating the page table, and restarting the instruction that caused the fault.
Example: Logical Address = (Page Number, Page Offset) Physical Address = (Frame Number, Page Offset) If Page Number = 5 and Page Offset = 200, and the page table entry for page 5 indicates Frame Number = 12, then the Physical Address is (12, 200).
Internal Fragmentation: Paging suffers from internal fragmentation because the last page of a process may not be fully utilized, but the entire page frame is allocated.
Segmentation
Segmentation is a memory management scheme that supports the programmer's view of memory. Memory is divided into logical units called segments. Segments can be of variable lengths.
-
Logical Address Structure: A logical address is divided into two parts:
- Segment Number (s): Identifies the segment.
- Segment Offset (d): The offset within the segment.
-
Segment Table: For each process, a segment table is maintained. Each entry in the segment table contains:
- Base: The starting physical address of the segment.
- Limit: The length of the segment.
-
Address Translation: To translate a logical address (s, d):
- Check if the offset 'd' is less than the limit 'limit'. If d >= limit, a trap is generated (segmentation fault).
- If d < limit, the physical address is calculated as: Physical Address = Base + d.
Advantages:
- Supports modular programming and sharing of segments.
- Protects segments from unauthorized access.
Disadvantages:
- External Fragmentation: Since segments are of variable length, memory can become fragmented into small holes, making it difficult to allocate large segments even if the total free memory is sufficient.
Demand Paging
Demand paging is a variation of paging that brings a page into memory only when it is needed (i.e., when a page fault occurs for that page). This is a widely used technique for implementing virtual memory.
- When a process starts, only its essential pages are loaded into memory.
- As the process executes, if it references a page that is not in memory, a page fault occurs.
- The operating system's page fault handler then finds the required page on secondary storage, loads it into a free frame in physical memory, updates the page table, and resumes the process.
- If there are no free frames, a page replacement algorithm is used to select a victim page to be swapped out of memory to make room for the new page.
Advantages:
- Reduced Memory Usage: Only the actively used pages of a process need to be in memory.
- Faster Process Startup: Processes can start executing immediately without waiting for all their pages to be loaded.
- More Processes in Memory: Allows more processes to be run concurrently than would be possible if all pages had to be loaded.
Disadvantages:
- Overhead: Page faults and page replacement algorithms introduce overhead in terms of time and system resources.
- Thrashing: If a process does not have enough frames allocated to it, it will spend most of its time swapping pages in and out, leading to very low CPU utilization and poor performance.
Storage Management
Storage management involves organizing and controlling the storage of data on secondary storage devices like hard disks and SSDs. This includes managing file systems, disk scheduling, and techniques for improving storage reliability and performance.
RAID (Redundant Array of Independent Disks)
RAID is a data storage virtualization technology that combines multiple physical disk drives into one or more logical units for the purposes of data redundancy, performance improvement, or both.
Common RAID Levels
| Level | Description | Redundancy | Performance | Minimum Disks |
|---|---|---|---|---|
| RAID 0 (Striping) | Data is split across multiple disks without redundancy. If one disk fails, all data is lost. | None | High (read/write performance) | 2 |
| RAID 1 (Mirroring) | Data is written identically to two or more disks. Provides high redundancy. | High (can tolerate failure of all but one disk) | Read: High, Write: Moderate | 2 |
| RAID 5 (Striping with Distributed Parity) | Data is striped across disks, and parity information is distributed across all disks. Offers a balance between performance, redundancy, and cost. Parity allows reconstruction of data if one disk fails. | Good (can tolerate failure of one disk) | Read: High, Write: Moderate (due to parity calculation) | 3 |
| RAID 6 (Striping with Dual Distributed Parity) | Similar to RAID 5 but uses two independent parity calculations distributed across all drives. Offers higher redundancy than RAID 5. | Very Good (can tolerate failure of two disks) | Read: High, Write: Lower than RAID 5 (more complex parity) | 4 |
| RAID 10 (or 1+0) (Mirrored Stripes) | Combines RAID 1 (mirroring) and RAID 0 (striping). Data is striped across mirrored pairs. High performance and redundancy. | High (can tolerate multiple disk failures as long as no mirrored pair fails completely) | Very High (read/write) | 4 |
RAID 0: Best for applications needing maximum speed and where data loss is acceptable (e.g., scratch disks for video editing).
RAID 1: Good for critical data where reliability is paramount (e.g., operating system drives, databases).
RAID 5/6: Common for file servers and general-purpose storage where a balance of cost, performance, and redundancy is needed. RAID 6 is preferred for larger arrays where the probability of a second failure during rebuild is higher.
RAID 10: Often the best choice for demanding applications like databases and high-transaction environments due to its excellent performance and redundancy.
- RAID 0: No Redundancy, 0 fault tolerance.
- RAID 1: Mirroring, 1 copy.
- RAID 5: Distributed Parity (think 5 is a prime number, spread out).
- RAID 6: Dual Parity (6 is 2 * 3, two levels of parity).
- RAID 10: 1+0 = Mirroring + Striping.
Disk Scheduling Algorithms
Disk scheduling is used to determine the order in which disk I/O requests will be serviced by the disk controller. The goal is to minimize the total seek time and rotational latency, thereby improving disk performance. This is crucial because disk I/O is much slower than CPU operations.
Key Concepts:
- Seek Time: The time taken for the disk arm to move to the correct track.
- Rotational Latency: The time taken for the desired sector to rotate under the read/write head.
- Transfer Time: The time taken to transfer the data.
Assume a disk with 200 tracks (0-199). The disk head is currently at track 53. The disk has received a request queue for I/O to tracks in the following order: 98, 183, 37, 122, 14, 124, 65, 67.
1. First-Come, First-Served (FCFS)
Service requests in the order they arrive.
Order: 53 → 98 → 183 → 37 → 122 → 14 → 124 → 65 → 67
Total Head Movement: |53-98| + |98-183| + |183-37| + |37-122| + |122-14| + |14-124| + |124-65| + |65-67| = 45 + 85 + 146 + 85 + 108 + 110 + 59 + 2 = 640 tracks
- Pros: Simple.
- Cons: Can lead to very long seek times if requests are scattered.
2. Shortest Seek Time First (SSTF)
Select the request with the minimum seek time from the current head position. It is a preemptive algorithm.
Current position: 53. Requests: {98, 183, 37, 122, 14, 124, 65, 67}
1. Closest to 53 is 65 (diff=12). Service 65. Head at 65. Remaining: {98, 183, 37, 122, 14, 124, 67} 2. Closest to 65 is 67 (diff=2). Service 67. Head at 67. Remaining: {98, 183, 37, 122, 14, 124} 3. Closest to 67 is 37 (diff=30). Service 37. Head at 37. Remaining: {98, 183, 122, 14, 124} 4. Closest to 37 is 14 (diff=23). Service 14. Head at 14. Remaining: {98, 183, 122, 124} 5. Closest to 14 is 98 (diff=84). Service 98. Head at 98. Remaining: {183, 122, 124} 6. Closest to 98 is 122 (diff=24). Service 122. Head at 122. Remaining: {183, 124} 7. Closest to 122 is 124 (diff=2). Service 124. Head at 124. Remaining: {183} 8. Closest to 124 is 183 (diff=59). Service 183. Head at 183. Remaining: {}
Order: 53 → 65 → 67 → 37 → 14 → 98 → 122 → 124 → 183
Total Head Movement: |53-65| + |65-67| + |67-37| + |37-14| + |14-98| + |98-122| + |122-124| + |124-183| = 12 + 2 + 30 + 23 + 84 + 24 + 2 + 59 = 236 tracks
- Pros: Generally provides better performance than FCFS.
- Cons: Can lead to starvation for requests that are far from the current head position.
3. SCAN (Elevator Algorithm)
The disk arm starts at one end of the disk and moves towards the other end, servicing all requests in its path. When it reaches the other end, it reverses direction and continues servicing requests.
Assume the disk arm moves from track 0 to 199 and then back to 0.
Scenario A: SCAN (moving towards 199) Current position: 53. Direction: Towards 199. Order: 53 → 65 → 67 → 98 → 122 → 124 → 183 → 199 (end) → 37 → 14
Total Head Movement (Scenario A): |53-199| + |199-14| = 146 + 185 = 331 tracks
Scenario B: C-SCAN (Circular SCAN) The arm moves from 0 to 199, servicing requests. When it reaches 199, it immediately jumps back to 0 without servicing any requests in between and starts scanning again from 0 to 199. This provides more uniform wait times.
Current position: 53. Direction: Towards 199. Order: 53 → 65 → 67 → 98 → 122 → 124 → 183 → 199 (end) → (jump to 0) → 14 → 37
Total Head Movement (C-SCAN): |53-199| + |199-0| + |0-37| = 146 + 199 + 37 = 382 tracks
- Pros: Avoids starvation. More uniform wait times than SSTF.
- Cons: Can over-service requests at the ends of the sweep. C-SCAN provides better uniformity.
4. LOOK and C-LOOK
Variations of SCAN and C-SCAN. Instead of moving to the end of the disk (0 or 199), the arm only moves to the last requested track in each direction and then reverses.
LOOK: Current position: 53. Direction: Towards highest track. Last request is 183. Order: 53 → 65 → 67 → 98 → 122 → 124 → 183 (last request in this direction) Reverse direction. Last request is 14. Order: → 37 → 14 (last request in this direction)
Total Head Movement (LOOK): |53-183| + |183-14| = 130 + 169 = 299 tracks
C-LOOK: Current position: 53. Direction: Towards highest track. Last request is 183. Order: 53 → 65 → 67 → 98 → 122 → 124 → 183 Reverse direction. Last request is 14. Order: → (jump to nearest request in the other direction, which is 14) → 14 → 37
Total Head Movement (C-LOOK): |53-183| + |183-14| = 130 + 169 = 299 tracks (In this specific example, LOOK and C-LOOK yield the same movement after the first sweep. C-LOOK's advantage is in its circular nature for subsequent sweeps.)