경쟁 상태

Race condition

동시에 읽고 쓴 작업의 순서에 따라 결과가 달라집니다.

···
html
<div class="v"><header><b>LOST UPDATE</b><span id="state"></span></header><main><div class="workers" id="workers"></div><div class="total" id="total"></div></main><footer>two increments can yield one</footer></div>
css
.v{width:min(92vw,660px);height:min(86vh,310px);box-sizing:border-box;padding:clamp(9px,2.5vmin,18px);border:1px solid var(--line);border-radius:14px;background:var(--surface);display:flex;flex-direction:column;gap:7px;color:var(--fg);font:500 clamp(15px,3.2vmin,17px)/1.25 var(--font-sans, sans-serif)}.v header,.v footer{display:flex;justify-content:space-between;align-items:center;gap:8px;white-space:nowrap}.v header b{color:var(--accent);font-size:.9em}.v header span,.v footer{color:var(--muted);font-size:.82em}.v main{flex:1;min-height:0;position:relative;overflow:hidden}.v .mono{font-family:ui-monospace,SFMono-Regular,Consolas,monospace}.v .active{background:var(--accent)!important;color:var(--bg)!important;border-color:var(--accent)!important}.v .muted{opacity:.28} .workers{height:67%;display:flex;justify-content:space-around;gap:8px}.worker{width:44%;border:1px solid var(--line);border-radius:7px;padding:8px;text-align:center;font:600 .82em ui-monospace,monospace}.worker b{display:block;margin-top:10px;color:var(--accent)}.total{text-align:center;color:var(--accent);font:700 .9em ui-monospace,monospace}
js
let n=0;const steps=[["read 0","read 0","counter = 0"],["write 1","read 0","counter = 1"],["done","write 1","counter = 1"],["read 1","write 2","counter = 2"]];function draw(){const s=steps[n];document.getElementById("workers").innerHTML="<div class=worker>WORKER A<b>"+s[0]+"</b></div><div class=worker>WORKER B<b>"+s[1]+"</b></div>";document.getElementById("total").textContent=s[2];document.getElementById("state").textContent=n===3?"serialized":"interleaved";n=(n+1)%4}draw();setInterval(draw,1050)

두 작업이 같은 값을 읽고 각각 1을 더해 저장하면 갱신 하나가 사라질 수 있습니다. 읽기와 쓰기가 분리된 여러 단계이기 때문입니다.

재현이 어려운 이유는 스케줄러와 I/O 타이밍에 따라 순서가 바뀌기 때문입니다. 데모에서 두 작업이 모두 0을 읽는 경우와 한 작업이 끝난 뒤 다른 작업이 읽는 경우를 비교합니다.

언제 쓰나

공유 카운터, 재고, 중복 요청처럼 여러 작업이 같은 상태를 바꿀 때 확인합니다.

페이지로 열기 ↗