LabHub
배우기 러닝패스 코스

디버깅 실전 · 순서가 보장되지 않아 생기는 것 · 실습

여덟 건이 들어왔는데 하나만 남았다

LabHub 에서 이어서 보기

목표

출발선을 맞춰 경쟁 조건을 재현 가능한 사실로 만든 뒤, 잃어버린 갱신을 배타 잠금으로 막고, 확인 후 사용의 틈을 원자적 생성으로 닫고, 통째로 쓰는 문서를 원자적 이름 바꾸기로 갈아 끼운다. 마지막으로 잠금을 잡기 전에 파일을 비우는 실수가 무엇을 날리는지 직접 확인한다.

왜 중요한가

경쟁 조건은 "가끔 숫자가 안 맞는다" 로 신고된다. 혼자 돌리면 언제나 맞기 때문에 조사가 재현에서 막힌다. 그런데 프로세스를 먼저 다 띄워 두고 출발 표식 하나로 동시에 보내면, 경쟁은 확률이 아니라 언제나 일어나는 일이 된다. 재현이 되는 순간부터 그것은 고칠 수 있는 결함이다.
막는 방법은 증상의 모양에 따라 다르다. 읽고 고쳐 쓰는 구간은 잠금으로 묶고, 확인 후 사용은 한 번의 호출로 바꾸고, 통째로 쓰는 파일은 이름 바꾸기로 갈아 끼운다. 이 셋을 섞어 쓰면 잠금을 걸어도 증상이 남는다.
가장 자주 걸리는 함정은 잠금의 범위다. open(path, "w") 는 여는 순간 파일을 비우므로, 그다음 줄에서 잠금을 잡아도 이미 늦었다. 이 실수는 잠금을 건 코드에서 나기 때문에 더 오래 살아남는다.
채점기는 여러분의 설명을 믿지 않는다. 채점기가 자기 하네스로 여러분의 워커를 실제로 동시에 띄워 최종 값과 승자 수를 직접 센다. 프로세스 수는 실행마다 바뀌므로 값을 외워 넣을 수 없습니다.

단계

1. /root/race/gen_race.py 를 만들어 실행해 /root/race/spawn.py(출발선 하네스)를 만드세요.
2. /root/race/naive_add.py 로 잠금 없는 갱신을 동시에 보내 /root/race/lost.json 에 잃어버린 갱신을 적으세요.
3. /root/race/locked_add.py 로 같은 일을 배타 잠금 안에서 하고 /root/race/lock.json 에 적으세요.
4. /root/race/claim.py 로 확인 후 사용의 틈을 닫고 /root/race/claim.json 에 승자와 패자를 적으세요.
5. /root/race/safe_write.py/root/race/read_probe.py 로 부분 기록을 막고 /root/race/atomic.json 에 적으세요.
6. /root/race/append_line.py 로 잠금 전에 파일을 비우지 않고 덧붙여 /root/race/append.json 에 적으세요.
7. 두 판을 여러 번 돌려 /root/race/evidence.json 에 재현 가능한 증거를 남기세요.
8. /root/race/summary.json/root/race/race_report.md 에 네 절로 보고하세요.

참고

단계 8개

  1. 출발선을 맞추는 하네스 손에 쥐기
  2. 여덟 건이 하나가 되는 것 보기
  3. 배타 잠금으로 한 덩어리 만들기
  4. 확인 후 사용의 틈 닫기
  5. 반쯤 쓰인 파일을 읽지 않게 하기
  6. 잠금 전에 파일을 비우는 실수
  7. 재현 가능한 증거 남기기
  8. 무엇을 잃었고 무엇으로 막았는지 보고하기