Fundamentals 29 min read

Mastering Process Context Switching: What the CPU Actually Does

This article breaks down the fundamentals of process context switching, explaining CPU registers, program counters, the three-step switch routine, trigger conditions, performance impact, monitoring tools, and practical optimization techniques to help interview candidates answer confidently.

Deepin Linux
Deepin Linux
Deepin Linux
Mastering Process Context Switching: What the CPU Actually Does

CPU Context Overview

The CPU context consists of general‑purpose registers, status flags, the stack pointer and the program counter (PC). These registers hold temporary data and the PC points to the next instruction to execute.

Process Context Switching Procedure

Save Current Context

When the scheduler decides to switch, it copies the current task’s registers, flags, stack pointer and PC into the task’s Process Control Block (PCB).

typedef struct PCB {
    int general_reg;   // general registers
    int status_reg;   // status flags
    int stack_ptr;    // stack pointer
    int program_counter; // PC
} PCB;

void save_context(PCB *current_pcb) {
    current_pcb->general_reg = get_general_reg();
    current_pcb->status_reg = get_status_reg();
    current_pcb->stack_ptr = get_stack_ptr();
    current_pcb->program_counter = get_pc();
}

Load New Task Context

The scheduler reads the next task’s PCB and restores the saved values into the CPU registers and PC.

void load_context(PCB *next_pcb) {
    set_general_reg(next_pcb->general_reg);
    set_status_reg(next_pcb->status_reg);
    set_stack_ptr(next_pcb->stack_ptr);
    set_pc(next_pcb->program_counter);
}

Jump to New Task

After loading, execution jumps to the address stored in the PC.

void switch_to_new_task() {
    int new_pc = get_pc();
    goto *new_pc; // jump to the new instruction address
}

Typical Triggers for a Context Switch

Time‑slice exhaustion : The scheduler preempts a running process when its allotted quantum expires.

Resource shortage : A process blocks on I/O, memory or other resources; the OS saves its state and runs another ready process.

Voluntary sleep : Calls to sleep() or similar cause the process to yield the CPU.

Priority preemption : A higher‑priority task becomes ready and forces the current lower‑priority task to be saved and swapped out.

Hardware interrupts : An interrupt handler saves the interrupted task’s context, runs the ISR, then restores the original context.

Example: Time‑slice expiration

void scheduler_on_timer_tick() {
    current_process->time_slice--;
    if (current_process->time_slice <= 0) {
        save_context(current_process->pcb);
        current_process->time_slice = 100; // reset quantum
        current_process = select_next_ready_process();
        load_context(current_process->pcb);
    }
}

Example: I/O block

void read_disk_data() {
    while (is_disk_busy()) {
        save_context(current_process->pcb);
        current_process->state = BLOCKED;
        switch_to_next_process();
    }
    disk_read();
}

Example: Voluntary sleep

void data_update_task() {
    while (1) {
        update_data();
        save_context(current_process->pcb);
        current_process->state = SLEEPING;
        sleep(1); // triggers a voluntary switch
        current_process->state = READY;
    }
}

Example: Priority preemption

void check_priority_preempt() {
    PCB *high_pcb = get_highest_priority_process();
    PCB *cur_pcb = current_process;
    if (high_pcb->priority > cur_pcb->priority) {
        save_context(cur_pcb);
        cur_pcb->state = READY;
        current_process = high_pcb;
        load_context(high_pcb);
    }
}

Example: Hardware interrupt

void keyboard_interrupt_handler() {
    save_context(current_process->pcb);
    int key = read_keyboard_data();
    process_key_input(key);
    load_context(current_process->pcb);
}

Performance Impact of Context Switching

CPU time overhead : Saving and restoring registers consumes cycles; frequent switches can consume a noticeable fraction of total CPU time.

TLB flushes : Switching processes invalidates the Translation Lookaside Buffer, forcing address‑translation recomputation and increasing memory latency.

Cache pollution : The new task’s working set is unlikely to be present in the CPU caches, causing cache misses and extra memory traffic.

Observing Context Switches

vmstat : vmstat [interval] [count] shows the cs column (context switches per second).

pidstat : pidstat -w [interval] [count] reports per‑process voluntary ( cswch/s) and non‑voluntary ( nvcswch/s) switches.

/proc filesystem : /proc/[pid]/task/[tid]/status contains voluntary_ctxt_switches and nonvoluntary_ctxt_switches for a thread.

Reducing Unnecessary Context Switches

CPU Affinity (Binding)

Pinning a process or thread to specific cores avoids cache invalidation across cores.

#define _GNU_SOURCE
#include <pthread.h>
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void* thread_function(void* arg) {
    int core = *((int*)arg);
    cpu_set_t cpuset;
    CPU_ZERO(&cpuset);
    CPU_SET(core, &cpuset);
    if (pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset) != 0) {
        perror("pthread_setaffinity_np");
        exit(EXIT_FAILURE);
    }
    while (1) {
        sleep(1);
    }
    return NULL;
}

int main() {
    pthread_t thread;
    int core = 0;
    if (pthread_create(&thread, NULL, thread_function, &core) != 0) {
        perror("pthread_create");
        exit(EXIT_FAILURE);
    }
    pthread_join(thread, NULL);
    return 0;
}

Command‑line equivalent:

taskset -c 0,1 ./my_program

Scheduling Policy Tuning

Adjust nice values (e.g., nice -n -5 ./critical_app) or use real‑time policies such as SCHED_FIFO and SCHED_RR for latency‑sensitive workloads.

Lock Optimizations

Reduce lock hold time by limiting the critical section.

Use finer‑grained locks (e.g., per‑object locks, ReadWriteLock for read‑heavy workloads).

Replace heavy mutexes with non‑blocking atomic operations ( AtomicInteger, AtomicLong) to avoid unnecessary switches caused by contention.

Performance optimizationLinuxOperating systemprocess schedulingcontext switch
Deepin Linux
Written by

Deepin Linux

Research areas: Windows & Linux platforms, C/C++ backend development, embedded systems and Linux kernel, etc.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.