Dead Lock(ꡐ착 μƒνƒœ)

2023. 3. 31. 22:38ㆍCS/CS μŠ€ν„°λ””

λ™μ‹œμ„± ν”„λ‘œκ·Έλž˜λ°μ„ μž‘μ„±ν•  λ•Œ, ν”„λ‘œκ·Έλž˜λ¨ΈλŠ” ꡉμž₯히 μ„Έμ‹¬ν•œ μ£Όμ˜κ°€ ν•„μš”ν•˜λ‹€.

λ‹¨μˆœνžˆ λ™μ‹œμ„± 문제λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•œ μƒν˜Έ λ°°μ œμ™€ 같은 기법을 μ‚¬μš© μ‹œ

이둜 μΈν•œ μ„±λŠ₯ μ €ν•˜μ™€ κ·Έ μ™Έμ˜ λ‹€μ–‘ν•œ μƒˆλ‘œμš΄ λ¬Έμ œλ“€μ„ 직면할 수 있기 λ•Œλ¬Έμ΄λ‹€.

그쀑 κ°€μž₯ 유λͺ…ν•œ 였λ₯˜κ°€ λ°”λ‘œ λ°λ“œλ½μ΄λ‹€.

 

λ°λ“œλ½μ΄λž€?

ꡐ착 μƒνƒœλΌκ³ λ„ λΆ€λ₯΄λŠ” λ°λ“œλ½μ€ λ™μ‹œμ„± ν”„λ‘œκ·Έλž˜λ°μ—μ„œ λ°œμƒν•˜λŠ” κ°€μž₯ 유λͺ…ν•œ 였λ₯˜ 쀑 ν•˜λ‚˜μ΄λ‹€.

좜처: https://sujinnaljin.medium.com/ios-%EC%B0%A8%EA%B7%BC%EC%B0%A8%EA%B7%BC-%EC%8B%9C%EC%9E%91%ED%95%98%EB%8A%94-gcd-14-4aefd4ba1eb7

μœ„ μ΄λ―Έμ§€λŠ” λ°λ“œλ½μ΄ λ°œμƒν•˜λŠ” 상황에 λŒ€ν•΄ 잘 μ„€λͺ…ν•˜κ³  μžˆλ‹€. 

μœ„ μ΄λ―Έμ§€μ—μ„œ 두 μŠ€λ ˆλ“œλŠ” 각각 곡유 μžμ›μ— λŒ€ν•œ 락을 νšλ“ν•œ μƒνƒœμ—μ„œ

μ„œλ‘œκ°€ 이미 νšλ“ν•œ 곡유 μžμ›μ— λŒ€ν•œ μ†Œμœ λ₯Ό μœ„ν•΄ λŒ€κΈ° μƒνƒœμ— λΉ μ§€κ²Œ λœλ‹€.

이런 λŒ€κΈ° 상황은 ν•΄μ†Œλ˜μ§€ λͺ»ν•œ 채 κ²°κ΅­ 두 μŠ€λ ˆλ“œ λͺ¨λ‘ μž‘λ™ν•˜μ§€ μ•Šκ²Œ λœλ‹€.

 

λ°λ“œλ½μ΄ λ°œμƒ 쑰건

λ°λ“œλ½μ΄ λ°œμƒν•˜κΈ° μœ„ν•΄μ„œλŠ” λ‹€μŒμ˜ 4가지 쑰건이 μΆ©μ‘±λ˜μ–΄μ•Ό ν•œλ‹€.

  • μƒν˜Έ 배제(Mutual Exclusion)
  • 점유 및 λŒ€κΈ°(Hold and Wait)
  • 비선점(Non-Preemption)
  • μˆœν™˜ λŒ€κΈ°(Circular Wait)

이λ₯Ό ν’€μ–΄μ„œ μ„€λͺ…ν•˜λ©΄,

각 μ“°λ ˆλ“œλŠ” μŠ€μŠ€λ‘œκ°€ ν•„μš”λ‘œ ν•˜λŠ” 곡유 μžμ›μ— λŒ€ν•œ λ…μžμ μΈ μ œμ–΄κΆŒ(락)을 νšλ“ν•˜λŠ” 상황 μ†μ—μ„œ, μŠ€λ ˆλ“œκ°€ 이미 νšλ“ν•œ μ œμ–΄κΆŒμ„ 가진채 λ‹€λ₯Έ 곡유 μžμ›μ— λŒ€ν•œ μ œμ–΄κΆŒμ„ μš”κ΅¬ν•΄μ•Ό ν•œλ‹€. λ§Œμ•½ λ‹€λ₯Έ μŠ€λ ˆλ“œμ—μ„œ 이미 점유 쀑이라면, 곡유 μžμ›μ΄ λ°˜ν™˜λ  λ•ŒκΉŒμ§€ λŒ€κΈ°ν•œλ‹€. μ΄λ•Œ λ‹€λ₯Έ μŠ€λ ˆλ“œκ°€ μ μœ ν•œ μžμ›μ„ λΊμ–΄μ˜¬ μˆ˜λŠ” μ—†λ‹€. λ§ˆμ§€λ§‰μœΌλ‘œ, μŠ€λ ˆλ“œλ“€ κ°„μ˜ λŒ€κΈ°κ°€ μˆœν™˜ ν˜•νƒœλ₯Ό 띠어야 ν•œλ‹€.

 

λ°λ“œλ½μ˜ 예방

μˆœν™˜ λŒ€κΈ° ν•΄μ†Œ

κ°€μž₯ 많이 μ‚¬μš©λ˜κ³ , 또 μ μš©ν•΄λ³Όλ§Œν•œ λ°©μ‹μœΌλ‘œ μˆœν™˜λŒ€κΈ°κ°€ λ°œμƒν•˜μ§€ μ•Šλ„λ‘ λ‘œμ§μ„ μž‘μ„±ν•˜λŠ” 방법이 μžˆλ‹€.

이λ₯Ό μœ„ν•΄μ„œλŠ”, 곡유 μžμ›μ„ νšλ“ν•˜λŠ” μˆœμ„œλ₯Ό 사전에 지정할 수 μžˆλ‹€.

예λ₯Ό λ“€μ–΄ μŠ€λ ˆλ“œ 1κ³Ό μŠ€λ ˆλ“œ 2κ°€ 각각 곡유 μžμ› A, B에 μ ‘κ·Όν•  λ•Œ,

μŠ€λ ˆλ“œ 1κ³Ό 2κ°€ 각각 A와 Bλ₯Ό λ¨Όμ € νšλ“ν•œ 채 λ‹€λ₯Έ ν•˜λ‚˜λ₯Ό λŒ€κΈ°ν•  λ•Œ λ°λ“œλ½μ΄ λ°œμƒν•œλ‹€.

이런 μƒν™©μ—μ„œ λ²—μ–΄λ‚˜κΈ° μœ„ν•΄ 무쑰건 Aλ₯Ό νšλ“ν•΄μ•Ό B에 λŒ€ν•œ μš”μ²­μ„ ν•  수 μžˆλ„λ‘ κ°•μ œν•˜λŠ” 것이닀.

κ·Έλ ‡κ²Œ 되면 μˆœν™˜ λŒ€κΈ° λ¬Έμ œκ°€ ν•΄κ²°λ˜μ–΄ λ°λ“œλ½μ„ μ˜ˆλ°©ν•  수 μžˆλ‹€. 

 

점유 및 λŒ€κΈ° ν•΄μ†Œ

ν•΄λ‹Ή 방식은 μš”κ΅¬λ˜λŠ” λͺ¨λ“  곡유 μžμ›μ— λŒ€ν•΄, 이λ₯Ό μ›μžμ μœΌλ‘œ ν•œλ²ˆμ— νšλ“ν•˜λ„λ‘ λ‘œμ§μ„ μž‘μ„±ν•˜λŠ” 것이닀.

마치 νŠΈλžœμž­μ…˜μ²˜λŸΌ 말이닀.

λ§Œμ•½ μš”κ΅¬λ˜λŠ” 곡유 μžμ› 쀑 ν•˜λ‚˜λΌλ„ νšλ“ν•˜μ§€ λͺ»ν•œλ‹€λ©΄,

λ‹€λ₯Έ μžμ›μ— λŒ€ν•œ νšλ“κΉŒμ§€λ„ μ—†λ˜ 일둜 λ§Œλ“€μ–΄μ„œ 이λ₯Ό ν•΄κ²°ν•  수 μžˆλ‹€.(λ‘€λ°±)

 

비선점 ν•΄μ†Œ

ν•΄λ‹Ή 방식은 νŠΉμ • μ“°λ ˆλ“œκ°€ μ—¬λŸ¬κ°œμ˜ 락을 μ–»κ³ μžν•  λ•Œ ν•˜λ‚˜λ₯Ό 얻은 μƒν™©μ—μ„œ

κ·Έ λ‹€μŒ 락을 얻을 λ•Œ λ§Œμ•½ ν•΄λ‹Ή 락이 이미 λ‹€λ₯Έ μŠ€λ ˆλ“œμ— 점유 쀑이면 기쑴에 νšλ“ν–ˆλ˜ 락을 λͺ¨λ‘ μ·¨μ†Œν•˜κ³ 

락 νšλ“ λ‘œμ§μ„ λ‹€μ‹œ μˆ˜ν–‰ν•˜λŠ” 것이닀.

λ§Œμ•½ λ‹€λ₯Έ μŠ€λ ˆλ“œμ—μ„œ 이와 λΉ„μŠ·ν•œ λ°©μ‹μœΌλ‘œ μˆœμ„œλŠ” λ‹€λ₯΄κ²Œ 락을 νšλ“ν•œλ‹€ν•΄λ„ λ°λ“œλ½ λ¬Έμ œλŠ” ν•΄μ†Œλœλ‹€.

비둝 λ‹€λ₯Έ μŠ€λ ˆλ“œκ°€ νšλ“ν•œ 락을 κ°•μ œλ‘œ λΊλŠ” 선점 κΈ°λŠ₯을 μΆ”κ°€ν•˜μ§€λŠ” μ•Šμ§€λ§Œ,

λ°λ“œλ½μ΄ λ°œμƒν•  수 μžˆλŠ” μƒν™©μ—μ„œ λ°”λ‘œ λŒ€κΈ°μ— 빠지지 μ•Šκ³  ν•΄λ‹Ή 상황을 νƒˆμΆœν•˜κ²Œ ν•΄μ€€λ‹€.

 

μƒν˜Έ 배제 ν•΄μ†Œ

ν•΄λ‹Ή 방식은 λ°λ“œλ½ 문제λ₯Ό μ™„ν™”ν•˜κΈ° μœ„ν•΄, μƒν˜Έ 배제 방식을 μ΅œμ†Œν™”ν•˜κΈ° μœ„ν•œ μ ‘κ·Ό 방식이닀.

즉 락을 μ΅œμ†Œν™”ν•˜λŠ” 것인데, 이λ₯Ό μœ„ν•΄ 비ꡐ κ΅ν™˜ 방식(Compare and Swap)을 μ‚¬μš©ν•  수 μžˆλ‹€.

비ꡐ κ΅ν™˜ 방식은 λ‹€μŒκ³Ό 같이 둜직 μž‘μ„±μ΄ 이루어진닀.

import threading

# 곡유 λ³€μˆ˜
count = 0


# μŠ€λ ˆλ“œ ν•¨μˆ˜
def atomic_increment():
    global count
    for i in range(100000):
        # 락을 μ‚¬μš©ν•˜μ§€ μ•Šκ³ , 비ꡐ-κ΅ν™˜ 연산을 μ‚¬μš©ν•˜μ—¬ count λ³€μˆ˜λ₯Ό μ¦κ°€μ‹œν‚΄
        while True:
            old_count = count
            new_count = old_count + 1
            if old_count == count:
                count = new_count
                break

# μŠ€λ ˆλ“œ 생성
worker_1 = threading.Thread(target=atomic_increment)
worker_2 = threading.Thread(target=atomic_increment)

# μŠ€λ ˆλ“œ μ‹€ν–‰
worker_1.start()
worker_2.start()

# μŠ€λ ˆλ“œ μ’…λ£Œ λŒ€κΈ°
worker_1.join()
worker_2.join()

# κ²°κ³Ό 좜λ ₯
print(count) # 200000

λ‘œμ§μ„ 보면

곡유 μžμ›μ˜ μƒνƒœλ₯Ό λ³΅μ‚¬ν•˜λŠ” λ³€μˆ˜λ₯Ό ν•˜λ‚˜ λ§Œλ“  ν›„ μˆ˜ν–‰ν•  연산을 이에 μ²˜λ¦¬ν•œλ‹€.

λ§Œμ•½ κ·Έ λ•ŒκΉŒμ§€λ„ λ³΅μ‚¬ν•œ κ°’κ³Ό 곡유 μžμ›μ˜ 값이 λ™μΌν•˜λ‹€λ©΄(λ‹€λ₯Έ μŠ€λ ˆλ“œλ₯Ό ν†΅ν•œ 연산이 μ²˜λ¦¬λ˜μ§€ μ•Šμ•˜λ‹€λ©΄)

μ—°μ‚° κ²°κ³Όλ₯Ό 곡유 μžμ›μ— λŒ€μž…ν•œλ‹€.

ν•΄λ‹Ή 방식은 락을 μ΅œμ†Œν™”ν•˜λŠ”λ° 도움을 μ£Όμ§€λ§Œ,

λ§Œμ•½ μˆ˜ν–‰ν•΄μ•Όν•  μ—°μ‚°μ˜ 규λͺ¨κ°€ 크닀면 곡유 μžμ›μ˜ μƒνƒœμ™€ 이λ₯Ό λ³΅μ‚¬ν•œ 값이 μΌμΉ˜ν•  ν™•λ₯ μ΄ 적어져

λ¬΄ν•œ 루프λ₯Ό νƒˆμΆœν•˜λŠ” λΉ„μœ¨μ΄ 쀄 수 있고, 또 운이 λ‚˜μ˜λ©΄ λ™μ‹œμ„± λ¬Έμ œκ°€ μ—¬μ „νžˆ λ°œμƒν•  수 있기 λ•Œλ¬Έμ— 만λŠ₯은 μ•„λ‹ˆλ‹€.

 

λ°λ“œλ½μ˜ νšŒν”Ό

μŠ€μΌ€μ€„λ§μ„ ν†΅ν•œ 방식

μŠ€λ ˆλ“œ 1κ³Ό μŠ€λ ˆλ“œ 2κ°€ λ°λ“œλ½ λ°œμƒ κ°€λŠ₯성이 μ‘΄μž¬ν•œλ‹€λŠ” 것을 사전에 인지할 수 μžˆλ‹€λ©΄,

ν•΄λ‹Ή μƒν™©μ—μ„œλŠ” μŠ€μΌ€μ€„λ§μ„ 톡해 λ°λ“œλ½μ„ ν”Όν•  수 μžˆλ‹€. 

μŠ€λ ˆλ“œ 1κ³Ό μŠ€λ ˆλ“œ 2κ°€ λ™μ‹œμ— μ‹€ν–‰λ˜λŠ” 상황이 λ¬Έμ œκ°€ λ˜λŠ” 것이기 λ•Œλ¬Έμ—,

μŠ€μΌ€μ€„λŸ¬κ°€ 이λ₯Ό μΈμ§€ν•˜κ³  μŠ€λ ˆλ“œ 1이 μ‹€ν–‰λ˜λŠ” λ™μ•ˆμ—λŠ” μŠ€λ ˆλ“œ 2λ₯Ό μ‹€ν–‰μ‹œν‚€μ§€ μ•ŠμœΌλ©΄ λ˜λŠ” 것이닀.

λ‹€λ§Œ ν•΄λ‹Ή 방식은 μŠ€λ ˆλ“œ κ°„ 병렬 처리λ₯Ό μ €ν•΄ν•  수 있기 λ•Œλ¬Έμ— μ„±λŠ₯적 μ΄μŠˆκ°€ λ°œμƒν•  μˆ˜λ„ μžˆλ‹€.

'CS > CS μŠ€ν„°λ””' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€

νŽ˜μ΄μ§€ ꡐ체 μ •μ±…  (0) 2023.04.04
μ„Έκ·Έλ©˜ν…Œμ΄μ…˜ & νŽ˜μ΄μ§• 기법  (0) 2023.04.04
Race Condition  (0) 2023.03.30
Mutex & Semaphore  (0) 2023.03.26
CPU μŠ€μΌ€μ€„λ§  (0) 2023.03.25