동기화(Synchronization)
- 동기화는 여러 스레드가 공유 자원에 동시에 접근할 때 발생하는 문제를 해결하기 위한 메커니즘
- 다수의 스레드가 동시에 공유 자원에 접근하면서 발생하는 경쟁 상태(Race Condition)를 방지하고, 일관성 있는 상태를 유지하기 위해 사용된다.
동기화 원리?
1. 상호 배제(Mutual Exclusion)
- 한 순간에는 오직 한 스레드만이 공유 자원을 사용할 수 있도록 한다.
- 이를 통해 다른 스레드가 동시에 접근하지 못하도록 한다.
2. 임계 영역(Critical Section)
- 공유 자원을 접근하는 코드 영역을 지칭한다.
- 이 영역에는 한 번에 한 스레드만 접근할 수 있도록 동기화 메커니즘이 적용된다.
예시: 은행 계좌 이체 시스템
조건 :
은행 계좌는 공유 자원이다.
여러 스레드가 동시에 이 계좌에 접근하여 입금 또는 출금을 수행할 수 있다.
출금과 입금은 원자적인 연산이어야 한다. 즉, 계좌의 잔액을 읽고 값을 수정하는 두 단계의 작업이 동시에 일어나야 한다.
출금과 입금 작업은 서로 동시에 일어나면 안 된다. 즉, 출금 작업이 진행되는 동안 입금 작업이 발생하면 안 된다.
이 조건을 충족하기 위해 동기화를 사용한다.
But 동기화를 잘못 사용하면 교착상태가 발생할 수 있다.
import threading
class BankAccount:
def __init__(self):
self.balance = 1000
self.lock = threading.Lock()
def deposit(self, amount):
with self.lock:
self.balance += amount
def withdraw(self, amount):
with self.lock:
if self.balance >= amount:
self.balance -= amount
return amount
else:
return 'Insufficient funds'
account = BankAccount()
# 출금과 입금 스레드 생성
def withdraw_money():
for _ in range(100):
account.withdraw(10)
def deposit_money():
for _ in range(100):
account.deposit(10)
withdraw_thread = threading.Thread(target=withdraw_money)
deposit_thread = threading.Thread(target=deposit_money)
# 스레드 실행
withdraw_thread.start()
deposit_thread.start()
# 스레드 종료 대기
withdraw_thread.join()
deposit_thread.join()
print(account.balance)
- 만약 위 코드에서 withdraw 메서드나 deposit 메서드에서 with self.lock: 부분을 제거하면 교착상태가 발생할 수 있다.
- 이 때 두 스레드가 동시에 withdraw와 deposit 메서드를 호출하여 상호 배제를 얻지 못하고 계속해서 공유 자원에 접근하려고 시도하게 된다.
- 이로 인해 두 스레드 모두 무한히 대기하며 교착상태가 발생한다.
교착상태(Deadlock)
- 교착상태는 여러 프로세스나 스레드가 서로 상대방의 작업이 끝나기만을 기다리면서 모두 진행하지 못하는 상태를 말한다.
- 이러한 상황은 각 프로세스나 스레드가 다른 자원을 점유하고 있으면서 상대방의 자원을 기다리기 때문에 발생한다.
교착상태 원리?
1. 상호 배제(Mutual Exclusion)
- 두 개 이상의 프로세스나 스레드가 동시에 자원을 점유할 수 없도록 한다.
2. 점유 대기(Hold and Wait)
- 이미 어떤 자원을 점유한 프로세스나 스레드가 다른 자원을 기다리면서 현재 자원을 계속 점유하는 상태를 말한다.
3. 비선점(No Preemption)
- 다른 프로세스나 스레드가 자원을 강제로 뺏어올 수 없도록 한다.
- 자원을 반납할 때까지 점유하게 된다.
4. 순환 대기(Circular Wait)
- 서로가 서로를 기다리는 순환 형태의 대기 상태
import threading
lock1 = threading.Lock()
lock2 = threading.Lock()
def func1():
lock1.acquire()
# func1이 lock1을 확보한 상태에서 lock2를 확보하기 위해 대기
lock2.acquire()
lock2.release()
lock1.release()
def func2():
lock2.acquire()
# func2가 lock2를 확보한 상태에서 lock1을 확보하기 위해 대기
lock1.acquire()
lock1.release()
lock2.release()
thread1 = threading.Thread(target=func1)
thread2 = threading.Thread(target=func2)
thread1.start()
thread2.start()
- 위의 예시에서는 두 개의 스레드가 서로 다른 락을 획득한 상태에서 다른 락을 획득하기 위해 대기하고 있다.
- 이러한 상황에서는 두 스레드가 서로 상대방이 가진 락을 대기하면서 무한히 실행을 멈추게 되며, 이것이 교착상태의 예시이다.
동기화는 상호 배제를 통해 한 번에 하나의 스레드만이 임계 영역에 접근할 수 있도록 한다.
But 잘못된 동기화나 교착 상태를 유발하는 상황을 피하기 위해서는 신중한 설계와 구현이 필요하다.
'CS' 카테고리의 다른 글
Call by Value vs. Call by Reference (0) | 2024.04.08 |
---|---|
오버플로우(Overflow) (0) | 2024.04.05 |
고차 함수와 재귀 함수 (0) | 2024.04.03 |
SQLite (0) | 2024.04.02 |
UUID 개념 및 생성 방법 (0) | 2024.04.01 |
동기화(Synchronization)
- 동기화는 여러 스레드가 공유 자원에 동시에 접근할 때 발생하는 문제를 해결하기 위한 메커니즘
- 다수의 스레드가 동시에 공유 자원에 접근하면서 발생하는 경쟁 상태(Race Condition)를 방지하고, 일관성 있는 상태를 유지하기 위해 사용된다.
동기화 원리?
1. 상호 배제(Mutual Exclusion)
- 한 순간에는 오직 한 스레드만이 공유 자원을 사용할 수 있도록 한다.
- 이를 통해 다른 스레드가 동시에 접근하지 못하도록 한다.
2. 임계 영역(Critical Section)
- 공유 자원을 접근하는 코드 영역을 지칭한다.
- 이 영역에는 한 번에 한 스레드만 접근할 수 있도록 동기화 메커니즘이 적용된다.
예시: 은행 계좌 이체 시스템
조건 :
은행 계좌는 공유 자원이다.
여러 스레드가 동시에 이 계좌에 접근하여 입금 또는 출금을 수행할 수 있다.
출금과 입금은 원자적인 연산이어야 한다. 즉, 계좌의 잔액을 읽고 값을 수정하는 두 단계의 작업이 동시에 일어나야 한다.
출금과 입금 작업은 서로 동시에 일어나면 안 된다. 즉, 출금 작업이 진행되는 동안 입금 작업이 발생하면 안 된다.
이 조건을 충족하기 위해 동기화를 사용한다.
But 동기화를 잘못 사용하면 교착상태가 발생할 수 있다.
import threading
class BankAccount:
def __init__(self):
self.balance = 1000
self.lock = threading.Lock()
def deposit(self, amount):
with self.lock:
self.balance += amount
def withdraw(self, amount):
with self.lock:
if self.balance >= amount:
self.balance -= amount
return amount
else:
return 'Insufficient funds'
account = BankAccount()
# 출금과 입금 스레드 생성
def withdraw_money():
for _ in range(100):
account.withdraw(10)
def deposit_money():
for _ in range(100):
account.deposit(10)
withdraw_thread = threading.Thread(target=withdraw_money)
deposit_thread = threading.Thread(target=deposit_money)
# 스레드 실행
withdraw_thread.start()
deposit_thread.start()
# 스레드 종료 대기
withdraw_thread.join()
deposit_thread.join()
print(account.balance)
- 만약 위 코드에서 withdraw 메서드나 deposit 메서드에서 with self.lock: 부분을 제거하면 교착상태가 발생할 수 있다.
- 이 때 두 스레드가 동시에 withdraw와 deposit 메서드를 호출하여 상호 배제를 얻지 못하고 계속해서 공유 자원에 접근하려고 시도하게 된다.
- 이로 인해 두 스레드 모두 무한히 대기하며 교착상태가 발생한다.
교착상태(Deadlock)
- 교착상태는 여러 프로세스나 스레드가 서로 상대방의 작업이 끝나기만을 기다리면서 모두 진행하지 못하는 상태를 말한다.
- 이러한 상황은 각 프로세스나 스레드가 다른 자원을 점유하고 있으면서 상대방의 자원을 기다리기 때문에 발생한다.
교착상태 원리?
1. 상호 배제(Mutual Exclusion)
- 두 개 이상의 프로세스나 스레드가 동시에 자원을 점유할 수 없도록 한다.
2. 점유 대기(Hold and Wait)
- 이미 어떤 자원을 점유한 프로세스나 스레드가 다른 자원을 기다리면서 현재 자원을 계속 점유하는 상태를 말한다.
3. 비선점(No Preemption)
- 다른 프로세스나 스레드가 자원을 강제로 뺏어올 수 없도록 한다.
- 자원을 반납할 때까지 점유하게 된다.
4. 순환 대기(Circular Wait)
- 서로가 서로를 기다리는 순환 형태의 대기 상태
import threading
lock1 = threading.Lock()
lock2 = threading.Lock()
def func1():
lock1.acquire()
# func1이 lock1을 확보한 상태에서 lock2를 확보하기 위해 대기
lock2.acquire()
lock2.release()
lock1.release()
def func2():
lock2.acquire()
# func2가 lock2를 확보한 상태에서 lock1을 확보하기 위해 대기
lock1.acquire()
lock1.release()
lock2.release()
thread1 = threading.Thread(target=func1)
thread2 = threading.Thread(target=func2)
thread1.start()
thread2.start()
- 위의 예시에서는 두 개의 스레드가 서로 다른 락을 획득한 상태에서 다른 락을 획득하기 위해 대기하고 있다.
- 이러한 상황에서는 두 스레드가 서로 상대방이 가진 락을 대기하면서 무한히 실행을 멈추게 되며, 이것이 교착상태의 예시이다.
동기화는 상호 배제를 통해 한 번에 하나의 스레드만이 임계 영역에 접근할 수 있도록 한다.
But 잘못된 동기화나 교착 상태를 유발하는 상황을 피하기 위해서는 신중한 설계와 구현이 필요하다.
'CS' 카테고리의 다른 글
Call by Value vs. Call by Reference (0) | 2024.04.08 |
---|---|
오버플로우(Overflow) (0) | 2024.04.05 |
고차 함수와 재귀 함수 (0) | 2024.04.03 |
SQLite (0) | 2024.04.02 |
UUID 개념 및 생성 방법 (0) | 2024.04.01 |