LOCK is a prefix byte (F0h). While the instruction after it runs, the 8086 activates its LOCK output pin, telling other bus masters (a second processor, the 8087, a DMA controller) not to take the bus. An instruction that reads memory and then writes it back, such as XCHG or INC on a memory operand, then cannot have another processor slip in between the read and the write.
A semaphore with XCHG
The classic use is a flag shared between processors. LOCK XCHG swaps a register with memory as one step: it stores 1 and returns what was there. If the old value was 0 the flag was free and you now own it; if it was 1 someone else has it and you try again. A plain MOV back to 0 releases it.
MOV AL, 1LOCK XCHG AL, FLAG1 ; take it; AL = the old valueMOV BL, AL ; 0: it was free, we own itMOV AL, 1LOCK XCHG AL, FLAG1 ; a second tryMOV BH, AL ; 1: already takenMOV AL, BLADD AL, '0' ; digit -> characterMOV DL, ALMOV AH, 02h ; DOS: print DLINT 21hMOV AL, BHADD AL, '0' ; digit -> characterMOV DL, ALMOV AH, 02h ; DOS: print DLINT 21hMOV FLAG1, 0 ; releaseFLAG1 DB 0
In a PC with a single 8086 or 8088, LOCK changes almost nothing that a program can see: interrupts only come between instructions anyway, so an instruction is already atomic as far as interrupt handlers are concerned. It matters for multiprocessor boards and for memory shared with other bus masters.
Pitfalls
LOCK REP with a string instruction is two prefixes, and an interrupt in the middle makes the 8086 resume with only the last one (see REP). On the 8086 the prefix can be put on any instruction.
Later CPUs: the 80386 and later accept LOCK only on read-modify-write instructions with a memory operand and raise an invalid-opcode exception otherwise, and an XCHG with memory locks the bus by itself, with or without the prefix.