Course contentsShow
← Embedded Systems & Computer Architecture
Lesson 537 of 9367. Real-Time Operating Systems (RTOS)Free lesson

Managing Shared Resources in Interrupt Service Routines

Apply safe synchronization techniques to share data between hardware interrupts and background tasks without causing system instability or deadlocks.

In this lesson, you will learn how to safely exchange data between hardware interrupts and background tasks without compromising system stability.

When an Interrupt Service Routine (ISR) needs to share data with a background task, you face a unique challenge: the ISR can preempt the task at any moment, and unlike standard tasks, the ISR cannot "wait" for a mutex or block on a semaphore. If an ISR attempts to lock a mutex that is already held by a task, the system may deadlock or trigger a kernel assertion because ISRs are not permitted to enter a blocked state.

The Problem: Preemption and Blocking

Imagine your background task is updating a shared sensor buffer. If an interrupt fires halfway through that update and tries to access the same buffer, it might read corrupted, "half-written" data. If you try to use a standard Mutex to protect that buffer, the ISR will crash the system because it lacks the context to "sleep" while waiting for the resource.

The Solution: Atomic Access and Deferred Processing

To maintain stability, you must strictly minimize the duration of shared access. For simple data, use Atomic Operations or volatile variables that can be modified in a single CPU cycle. For more complex structures, the standard approach is to use a "lock-free" buffer or delegate the processing to a task.

// Shared variable updated by ISR
volatile uint32_t sensor_reading;

void ISR_Handler(void) {
    // Only perform the absolute minimum: copy the value
    sensor_reading = Hardware_Read_Register();
    
    // Use a task notification to wake a background task
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    vTaskNotifyGiveFromISR(xProcessingTaskHandle, &xHigherPriorityTaskWoken);
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

By keeping the ISR logic restricted to simple updates or pushing data into a thread-safe structure (like a queue designed for ISR use), you prevent the ISR from needing to lock resources. The background task then processes the data asynchronously, safely managing the shared resource without the risk of an ISR-induced deadlock. Always prioritize keeping ISRs short and avoiding any mechanism that triggers a context switch or blocking state within the interrupt context.

Key Takeaway: Never attempt to block or acquire a mutex inside an ISR; instead, use atomic variables or ISR-safe primitives to pass data to a background task for processing.