Katkat

Reason About Deadlocks, Synchronization, False Sharing, and Privilege Transitions

NetappSystem Software Engineer · Technical Screen

Last updated

Analyze systems programming fundamentals across concurrency, memory architectures, and kernel execution through three concrete engineering scenarios.

Overview

In storage and operating system development, low-level concurrency and CPU-memory interactions directly dictate system reliability and throughput. Review the three scenarios below and provide technical answers distinguishing synchronization primitives, hardware cache behavior, and OS privilege transitions.


Scenario 1: Deadlock and Lock Ordering

Consider two worker threads running the following routines on shared resources protected by mutexes lock_x and lock_y:

void worker_transfer_forward() {
    pthread_mutex_lock(&lock_x);
    pthread_mutex_lock(&lock_y);
    /* perform transfer X -> Y */
    pthread_mutex_unlock(&lock_y);
    pthread_mutex_unlock(&lock_x);
}

void worker_transfer_backward() {
    pthread_mutex_lock(&lock_y);
    pthread_mutex_lock(&lock_x);
    /* perform transfer Y -> X */
    pthread_mutex_unlock(&lock_x);
    pthread_mutex_unlock(&lock_y);
}
  1. Name the four Coffman conditions for deadlocks. Which specific condition is violated or present here that triggers the hazard?
  2. Provide the standard design pattern to eliminate this deadlock without reducing the lock granularity.

Scenario 2: Cache Performance and Primitives

Two threads execute on distinct physical CPU cores. Each thread frequently increments its own 64-bit performance counter:

struct ThreadStats {
    uint64_t thread_0_ops; // modified exclusively by Thread 0
    uint64_t thread_1_ops; // modified exclusively by Thread 1
} stats;
  1. Explain why this design suffers severe throughput degradation even though threads access entirely separate member variables without lock contention.
  2. How would you resolve this issue in C/C++?
  3. When would you prefer a spinlock over a mutex for synchronizing shared state, and what hardware/scheduler risk does a spinlock introduce on a single-core system or under preemption?

Scenario 3: Privilege Transitions and Faults

  1. Contrast the CPU mechanics of a user-space thread issuing a valid read() system call versus a thread dereferencing an invalid pointer that raises a SIGSEGV.
  2. Clearly define the difference between blocking (as in pthread_mutex_lock), busy-waiting (as in pthread_spin_lock), and a hardware protection fault.

Hints

Hint 1

Focus on how global lock hierarchy prevents circular wait conditions across competing threads.

Hint 2

Think about cache lines (typically 64 bytes) and cache invalidation protocols like MESI when variables share a cache line.

Hint 3

Trace the CPU's transition from user ring 3 to kernel ring 0 via interrupt/exception vectors, noting whether the operation is synchronous/intentional or a trap.

Follow-up questions

  • How does Thread-Local Storage (TLS) help avoid both lock contention and false sharing in high-frequency logging or statistics?
  • What is priority inversion, and how do priority inheritance protocols resolve it when mutexes are held across threads of differing priorities?
  • How does the operating system kernel handle a page fault for a valid, lazily-allocated page compared to an invalid memory access resulting in segmentation violation?