35
3.4 Concurrency: Time Is of the Essence 병행성 : 시간은 중요하다 http://ohyecloudy.com http://cafe.naver.com/architect1.cafe 2009.3.14

[SICP] 3.4 Concurrency : Time is of the essence - 병행성 : 시간은 중요하다

  • Upload
    -

  • View
    1.515

  • Download
    5

Embed Size (px)

Citation preview

Page 1: [SICP] 3.4 Concurrency : Time is of the essence - 병행성 : 시간은 중요하다

3.4 Concurrency: Time Is of the Essence

병행성 : 시간은 중요하다

http://ohyecloudy.com

http://cafe.naver.com/architect1.cafe

2009.3.14

Page 2: [SICP] 3.4 Concurrency : Time is of the essence - 병행성 : 시간은 중요하다

덮어쓰기 연산

• 물체에 상태를 부여

• 계산 방법에 시갂 개념 추가

• 만약 없다면 시갂의 영향을 받지 않고 한결같아 진다.

(withdraw 25)

75 (withdraw 25)

50

Page 3: [SICP] 3.4 Concurrency : Time is of the essence - 병행성 : 시간은 중요하다

병행 시스템에서 시간의 본질 (define (withdraw amount) (if (>= balance amount) (begin (set! balance (- balance amount)) balance) "Insufficient funds"))

100

90

75

잔액 조회 : 100

새 값 : 100 – 10 = 90

잔액을 90으로 set!

잔액 조회 : 100

새 값 : 100 – 25 = 75

잔액을 75로 set!

Page 4: [SICP] 3.4 Concurrency : Time is of the essence - 병행성 : 시간은 중요하다

병행 프로그램의 올바른 동작

• 변수 하나에 여러 프로세스가 값을 덮어쓰려고 하는게 문제를 복잡하게 하고 있다.

• 상태 변화가 병행으로 일어날 때 예측 가능하게 동작하도록 병행 처리에 제약을 준다.

Page 5: [SICP] 3.4 Concurrency : Time is of the essence - 병행성 : 시간은 중요하다

병행 처리에 제약을 주는 방법

• 상태 변수 하나를 같이 사용 – 값을 바꿀 수 있는 연산 두 개가 동시에 돌아가지 못하게 제약

• 차례대로 돌아가게 만들어 병행 프로그램과 같은 결과를 만들어 낸다. – 어떤 차례인지 결정하지 않으면 올바른 결과가 여러 개다.

• 열의 퍼짐 시뮬레이션(flow of heat in an object)

– 여러 개의 프로세스 – 자기 값과 이웃 값의 평균으로 자기 값 수정 – 되풀이 하다보면 올바른 값으로 수렴

Page 6: [SICP] 3.4 Concurrency : Time is of the essence - 병행성 : 시간은 중요하다

병행 프로세스를 다루기 어려운 까닭

• 여러 프로세스에서 일어나는 사건의 차례가 서로 뒤엉킬 수 있기 때문

• 모든 경우를 하나하나 따져봐야 한다.

• 사건이 많아질수록 경우의 수가 폭발적으로 증가한다.

– (a,b,c,d,e,f) 사건이 차례대로 일어나는 A 프로세스와 (x,y,z,w) 사건이 차례대로 일어나는 B 프로세스가 있다면???

Page 7: [SICP] 3.4 Concurrency : Time is of the essence - 병행성 : 시간은 중요하다

parallel-execute

(define x 10) (parallel-execute (lambda () (set! x (* x x))) ; P1 (lambda () (set! x (+ x 1)))) ; P2

두 프로세스가 끝난 다음 나올 수 있는 x의 값 101 : a b c ㄱ ㄴ 121 : ㄱ ㄴ a b c 110 : a ㄱ ㄴ b c 11 : ㄱ a b c ㄴ 100 : a b ㄱ ㄴ c

P1 : a (첫 번째 x 읽기), b (두 번째 x 읽기), c (x를 덮어쓰기)

P2 : ㄱ (x 읽기), ㄴ (x를 덮어쓰기)

Page 8: [SICP] 3.4 Concurrency : Time is of the essence - 병행성 : 시간은 중요하다

병행성을 다스리는 방법

• 서로 뒤엉켜 돌아가는 여러 프로세스에 어떤 제약을 걸어서, 프로그램이 제대로 돌아갂다고 믿을 수 있도록 병행 시스템을 설계하는 방법이 필요하다.

• 줄 세우개(serializer)가 한가지 방법.

Page 9: [SICP] 3.4 Concurrency : Time is of the essence - 병행성 : 시간은 중요하다

줄 세우개(serializer)

• 병행으로 돌아가지 못하는 프로시저를 정의

• 여러 프로세스가 함께 쓰는 변수를 다스릴 수 있다.

Page 10: [SICP] 3.4 Concurrency : Time is of the essence - 병행성 : 시간은 중요하다

make-serializer

(define x 10) (define s (make-serializer)) (parallel-execute (s (lambda () (set! x (* x x)))) ; P1 (s (lambda () (set! x (+ x 1))))) ; P2

두 프로세스가 끝난 다음 나올 수 있는 x의 값 101 : a b c ㄱ ㄴ 121 : ㄱ ㄴ a b c 110 : a ㄱ ㄴ b c 11 : ㄱ a b c ㄴ 100 : a b ㄱ ㄴ c

P1 : a (첫 번째 x 읽기), b (두 번째 x 읽기), c (x를 덮어쓰기)

P2 : ㄱ (x 읽기), ㄴ (x를 덮어쓰기)

Page 11: [SICP] 3.4 Concurrency : Time is of the essence - 병행성 : 시간은 중요하다

줄 세우개를 사용한 은행 계정

• 잒액을 변경하는 withdraw, deposit 프로시저를 같은 줄 세우개를 사용해 동시에 실행할 수 없게 제한했다.

• 줄 세우개는 계정마다 하나씩 가진다.

–서로 다른 계정의 작업은 병행으로 이루어진다.

Page 12: [SICP] 3.4 Concurrency : Time is of the essence - 병행성 : 시간은 중요하다

(define (make-account balance) (define (withdraw amount) (if (>= balance amount) (begin (set! balance (- balance amount)) balance) "Insufficient funds")) (define (deposit amount) (set! balance (+ balance amount)) balance) (let ((protected (make-serializer))) (define (dispatch m) (cond ((eq? m 'withdraw) (protected withdraw)) ((eq? m 'deposit) (protected deposit)) ((eq? m 'balance) balance) (else (error "Unknown request -- MAKE-ACCOUNT" m)))) dispatch))

Page 13: [SICP] 3.4 Concurrency : Time is of the essence - 병행성 : 시간은 중요하다

연습 3.41

(define (make-account balance) (define (withdraw amount) (if (>= balance amount) (begin (set! balance (- balance amount)) balance) "Insufficient funds")) (define (deposit amount) (set! balance (+ balance amount)) balance) (let ((protected (make-serializer))) (define (dispatch m) (cond ((eq? m 'withdraw) (protected withdraw)) ((eq? m 'deposit) (protected deposit))

((eq? m 'balance) ((protected (lambda () balance)))) ; serialized (else (error "Unknown request -- MAKE-ACCOUNT" m)))) dispatch))

balance에 손을 댈 때 줄 세우기를 하지 않으면 제대로 돌아가지 않을 수도 있다는데 동의?

Page 14: [SICP] 3.4 Concurrency : Time is of the essence - 병행성 : 시간은 중요하다

연습 3.41 풀이

• 줄 세우기를 한 결과 withdraw, deposit과 balance는 동시에 실행되지 않는다.

• balance는 값을 변경하는 동작이 아니라 값을 읽는 동작을 하는 프로시저.

• Ben은 balance를 거래 후 잒액으로 생각.

• 동의하지 않음.

• balance 프로시저를 실행하는 그 시갂에 잒액을 보여줘야 한다고 생각한다.

Page 15: [SICP] 3.4 Concurrency : Time is of the essence - 병행성 : 시간은 중요하다

연습 3.42

(define (make-account balance) (define (withdraw amount) (if (>= balance amount) (begin (set! balance (- balance amount)) balance) "Insufficient funds")) (define (deposit amount) (set! balance (+ balance amount)) balance) (let ((protected (make-serializer)))

(let ((protected-withdraw (protected withdraw)) (protected-deposit (protected deposit))) (define (dispatch m) (cond ((eq? m 'withdraw) protected-withdraw) ((eq? m 'deposit) protected-deposit) ((eq? m 'balance) balance) (else (error "Unknown request -- MAKE-ACCOUNT" m)))) dispatch)))

이렇게 만들어도 괜찮은가? 변경 젂 make-account와 병행성에 어떤 차이가 나는가?

Page 16: [SICP] 3.4 Concurrency : Time is of the essence - 병행성 : 시간은 중요하다

연습 3.42 풀이

• 상관 없다.

• 이젂과 상관없이 make-serializer는 은행 계정 하나당 하나가 존재한다.

• make-serializer 프로시저를 실행하는 프로시저를 미리 만들어서 같은 프로시저를 내놓는다고 하더라도 줄 세운 프로시저가 같이 쓰는 뮤텍스와 같은 동기화 수단에 의존하기 때문

• 그렇기 때문에 병행성 또한 차이가 없다.

• 뒤에 make-serializer 구현 참조.

Page 17: [SICP] 3.4 Concurrency : Time is of the essence - 병행성 : 시간은 중요하다

여러 자원을 함께 쓰는 문제

• 이제 까지 자원 하나를 여럾이 쓰는 예제.

–폴과 피터가 같이 쓰는 생활비 은행 계좌

• 여러 자원을 함께 쓰는 경우를 살펴보자.

–두 은행 계정의 남은 돈을 맞바꾸는 일.

Page 18: [SICP] 3.4 Concurrency : Time is of the essence - 병행성 : 시간은 중요하다

exchange

• difference 변수에 값을 할당 후 withdraw, deposit 프로시저 호출 젂에 account1, account2의 balance가 변경될 수 있다.

(define (exchange account1 account2) (let ((difference (- (account1 'balance) (account2 'balance)))) ((account1 'withdraw) difference) ((account2 'deposit) difference)))

Page 19: [SICP] 3.4 Concurrency : Time is of the essence - 병행성 : 시간은 중요하다

해결 방법

• 두 계정의 줄 세우개를 사용해 exchange 프로시저 젂체를 줄 세운 프로시저로 만든다.

• 계정 속의 줄 세우개를 밖으로 노출 시켜야 한다.

–모듈 방식이 깨짐

–현재로선 다른 방법이 없다.

Page 20: [SICP] 3.4 Concurrency : Time is of the essence - 병행성 : 시간은 중요하다

(define (make-account-and-serializer balance) (define (withdraw amount) (if (>= balance amount) (begin (set! balance (- balance amount)) balance) "Insufficient funds")) (define (deposit amount) (set! balance (+ balance amount)) balance) (let ((balance-serializer (make-serializer))) (define (dispatch m) (cond ((eq? m 'withdraw) withdraw) ((eq? m 'deposit) deposit) ((eq? m 'balance) balance) ((eq? m 'serializer) balance-serializer) (else (error "Unknown request -- MAKE-ACCOUNT" m)))) dispatch))

Page 21: [SICP] 3.4 Concurrency : Time is of the essence - 병행성 : 시간은 중요하다

serialized-exchange

• 두 계정의 줄 세우개 serializer1, serializer2를 사용해 exchange 프로시저 젂체를 줄 세운 프로시저로 만들었다.

(define (serialized-exchange account1 account2) (let ((serializer1 (account1 'serializer)) (serializer2 (account2 'serializer))) ((serializer1 (serializer2 exchange)) account1 account2)))

Page 22: [SICP] 3.4 Concurrency : Time is of the essence - 병행성 : 시간은 중요하다

연습문제 3.44

(define (transfer from-account to-account amount) ((from-account 'withdraw) amount) ((to-account 'deposit) amount))

돈을 맞바꾸는 문제처럼 transfer 프로시저 자체를 줄 세운 프로시저로 만들어야 하는가?

Page 23: [SICP] 3.4 Concurrency : Time is of the essence - 병행성 : 시간은 중요하다

연습문제 3.44 풀이

• 필요 없다.

• 돈을 맞바꾸는 경우에는 두 은행 계정의 남은 돈의 차이를 계산한 후에 인터럽트가 걸린 경우 두 은행 계정의 남은 돈 차이가 변할 수 있기 때문에 돈을 맞바꾸는 프로시저 젂체를 줄 세운 프로시저로 만들었다.

• 돈을 옮기는 프로시저의 경우 인터럽트가 걸려도 프로시저 동작에 이상 없다.

Page 24: [SICP] 3.4 Concurrency : Time is of the essence - 병행성 : 시간은 중요하다

연습문제 3.45

(define (make-account-and-serializer balance) (define (withdraw amount) (if (>= balance amount) (begin (set! balance (- balance amount)) balance) "Insufficient funds")) (define (deposit amount) (set! balance (+ balance amount)) balance) (let ((balance-serializer (make-serializer))) (define (dispatch m)

(cond ((eq? m 'withdraw) (balance-serializer withdraw)) ((eq? m 'deposit) (balance-serializer deposit)) ((eq? m 'balance) balance) ((eq? m 'serializer) balance-serializer) (else (error "Unknown request -- MAKE-ACCOUNT" m)))) dispatch))

serialized-exchange를 불러 쓸 때 어떤 일이 일어나는지 따져라

Page 25: [SICP] 3.4 Concurrency : Time is of the essence - 병행성 : 시간은 중요하다

연습문제 3.45 풀이

• serialized-exchange 프로시저는 두 계정의 줄 세우개로 프로시저 젂체를 줄 세운 프로시저로 만든다.

• 안에서 exchange 프로시저를 실행하는데, withdraw, deposit 프로시저가 실행되지 않고 하염없이 기다린다.

• 계정의 줄 세우개로 프로시저를 실행했기 때문에.

Page 26: [SICP] 3.4 Concurrency : Time is of the essence - 병행성 : 시간은 중요하다

make-serializer 구현

• 뮤텍스 (mutex)

– mutual exclusion : 상호 배제

–뮤텍스 물체를 쥐거나(acquired) 풀어 주는(release) 연산

–한 프로세스가 뮤텍스를 잡으면 풀어 놓을 때까지 다른 프로세스가 뮤텍스를 잡지 못한다.

• 줄 세우개 하나에 뮤텍스 하나.

Page 27: [SICP] 3.4 Concurrency : Time is of the essence - 병행성 : 시간은 중요하다

(define (make-serializer) (let ((mutex (make-mutex))) (lambda (p) (define (serialized-p . args) (mutex 'acquire) (let ((val (apply p args))) (mutex 'release) val)) serialized-p)))

(define (make-mutex) (let ((cell (list false))) (define (the-mutex m) (cond ((eq? m 'acquire) (if (test-and-set! cell) (the-mutex 'acquire))) ; 재시도 ((eq? m 'release) (clear! cell)))) the-mutex)) (define (clear! cell) (set-car! cell false))

Page 28: [SICP] 3.4 Concurrency : Time is of the essence - 병행성 : 시간은 중요하다

test-and-set! 구현

(define (test-and-set! cell) (if (car cell) true (begin (set-car! cell true) false)))

• 이렇게 구현하면 제대로 동작 안 한다.

• 병행성 제어를 집어넣어야 할 곳

• 한 알갱이로(atomically) 처리되어야 한다.

–하드웨어 수준에서 지원하는 프로시저를 사용.

– MIT Scheme : without-interrupts

Page 29: [SICP] 3.4 Concurrency : Time is of the essence - 병행성 : 시간은 중요하다

연습문제 3.47

세마포어(semaphore)를 뮤텍스와 test-and-set!을 써서 만들어라. - 잡았다 놓았다 하는 연산은 뮤텍스와 같지만 n개 프로세스가 병행으로 세마포어를 쥘 수 있다. - 뮤텍스를 사용하는 것만 풀이

Page 30: [SICP] 3.4 Concurrency : Time is of the essence - 병행성 : 시간은 중요하다

연습문제 3.47 풀이 (define (new-make-semaphore n) (let ((count 0) (mutex (make-mutex))) (define (the-semaphore m) (cond ((eq? m 'acquire) (mutex 'acquire) (cond ((> count n) (mutex 'release) (the-semaphore 'acquire)) ; 재시도 (else (set! count (+ count 1)) (mutex 'release)))) ((eq? m 'release) (mutex 'acquire) (if (< count 0) (set! count (- count 1))) (mutex 'release)))) the-semaphore))

Page 31: [SICP] 3.4 Concurrency : Time is of the essence - 병행성 : 시간은 중요하다

데드락 (deadlock)

• 여러 프로세스가 다른 프로세스를 지켜보면서 아무것도 하지 못하고 끝없이 기다려야 하는 상태

• 돈 맞바꾸는 문제의 경우에는 계정마다 번호를 매겨 놓고 모든 프로세스가 언제나 번호가 낮은 계정을 움켜쥐고 일을 시작하도록 하면 해결 가능.

Page 32: [SICP] 3.4 Concurrency : Time is of the essence - 병행성 : 시간은 중요하다

연습문제 3.48

계정에 번호를 매겨, 각 프로세스가 처음에 더 작은 번호를 매긴 계정을 움켜쥐도록 만들어서 데드락을 피하는 기법을 사용. 왜 돈 맞바꾸는 문제에서 데드락에 빠지지 않는가? 그 방법대로 serialized-exchange 프로시저를 작성.

Page 33: [SICP] 3.4 Concurrency : Time is of the essence - 병행성 : 시간은 중요하다

연습문제 3.48 풀이 (define (make-account-and-serializer id balance) (define (withdraw amount) (if (>= balance amount) (begin (set! balance (- balance amount)) balance) "Insufficient funds")) (define (deposit amount) (set! balance (+ balance amount)) balance) (let ((balance-serializer (make-serializer))) (define (dispatch m) (cond ((eq? m 'withdraw) withdraw) ((eq? m 'deposit) deposit) ((eq? m 'balance) balance) ((eq? m 'id) id) ((eq? m 'serializer) balance-serializer) (else (error "Unknown request -- MAKE-ACCOUNT" m)))) dispatch))

Page 34: [SICP] 3.4 Concurrency : Time is of the essence - 병행성 : 시간은 중요하다

(define (serialized-exchange account1 account2) (let ((serializer1 (account1 'serializer)) (serializer2 (account2 'serializer))) (if (< (account1 'id) (account2 'id)) ((serializer2 (serializer1 exchange)) account1 account2) ((serializer1 (serializer2 exchange)) account1 account2))))

연습문제 3.48 풀이(계속)

• 비교 대상이 되는 id가 있어서 어떠한 계정 두개를 가져다 놓더라도 줄 세우는 방법은 한가지 밖에 없다. 그래서 데드락에 빠지지 않는다.

Page 35: [SICP] 3.4 Concurrency : Time is of the essence - 병행성 : 시간은 중요하다