another consumer thread only). // End of critical sections. // Release "queueLock" until we need it again to take the next task. queueLock.release(); // Go off and do something with the task. doStuff(myTask); } } Synchronization primitives Implementing mutexes and condition variables requires some kind of synchronization primitive provided by hardware support that provides atomicity. Locks and condition variables are higher-level abstractions over these synchronization primitives. On a uniprocessor, disabling and enabling interrupts is a way to implement monitors by preventing context switches during the critical sections of the locks and condition variables, but this is not enough on a multiprocessor. On a multiprocessor, usually special atomic read-modify-write instructions on the memory such as test-and-set, compare-and-swap, etc. are used, depending on what the instruction set architecture provides. These usually require deferring to spin-locking for the internal lock state itself, but this locking is very brief. Depending on the implementation, the atomic read-modify-write instructions may lock the bus from other cores' accesses and/or prevent re-ordering of instructions in the CPU. Here is an example pseudocode implementation of parts of a threading system and mutexes and Mesa-style condition variables, using test-and-set and a first-come, first-served policy. This glosses over most of how a threading system works, but shows the parts relevant to mutexes and condition variables: Sample Mesa-monitor implementation with Test-and-Set // Basic parts of threading system: // Assume "ThreadQueue" supports random access. public volatile ThreadQueue readyQueue; // Thread-unsafe queue of ready threads. Elements are (Thread*). public volatile global Thread* currentThread; // Assume this variable is per-core. (Others are shared.) // Implements a spin-lock on just the synchronized state of the threading system itself. // This is used with test-and-set as the synchronization primitive. public volatile global bool threadingSystemBusy = false; // Context-switch interrupt service routine (ISR): // On the current CPU core, preemptively switch to another thread. public method contextSwitchISR() { if (testAndSet(threadingSystemBusy)) { return; // Can't switch context right now. } // Ensure this interrupt can't happen again which would foul up the context switch: systemCall_disableInterrupts(); // Get all of the registers of the currently-running process. // For Program Counter (PC), we will need the instruction location of // the "resume" label below. Getting the register values is platform-dependent and may involve // reading the current stack frame, JMP/CALL instructions, etc. (The details are beyond this scope.) currentThread->registers = getAllRegisters(); // Store the registers in the "currentThread" object in memory.