exercise 3.47~49
ようやく3.4終了。
ページ自体は短かったが、意外に時間がかかったなぁ。
少し長いので続きを読むから。
ex3.48
;;mutexなやつ。 (define (make-semaphore n) (let ((mutex (make-mutex))) (define (acquire) (mutex 'acquire) (if (> n 0) (set! n (- n 1)) (begin (mutex 'release) (acquire))) (mutex 'release)) (define (release) (mutex 'acquire) (set! x (+ x 1)) (mutex 'release)) (define (the-semaphore m) (cond ((eq? m 'acquire) (acquire)) ((eq? m 'release) (release)) (else (error "Unknown Operation -- SEMAPHORE" m)))\ ) the-semaphore))
もうひとつはパス。
というか、よくわからんので、解答例見た・・・.orz
よーするにtest-and-set!とcellを使って、nをいじったりする部分に入れるのは1プロセスだけになるようにしときゃいいのか。ほむほむ。
もっと精進せねばなぁ・・・
ex3.48
accountにnumberを割り振っておき、小さい順にアクセスしていけば、PeterもPaulも同じ順番であa1,a2のaccountにアクセスするのでDeadLockは避けれる。
あー、説明しにくい。
コードは適当に書いた↓
(define (make-account-and-serializer-and-number balance number) (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) ((eq? m 'number) number) (else (error "Unknown request -- MAKE-ACCOUNT" m)))) dispatch)) (define (serialized-exchange account1 account2) (let ((number1 (account1 'number)) (number2 (account2 'number)) (serializer1 (account1 'serializer)) (serializer2 (account2 'serializer))) ((if (< number1 number2) (serializer1 (serializer2 exchange)) (serializer2 (serializer1 exchange))) account1 account2)))
make-account-and-serializer-and-numbr
・・・なんて適当な名前!!!
まぁいいや、きっとこれでいいはず。
ex3.49
うまい例が思い浮かばない・・・。
以下は適当な妄想。
というか推敲せずに書きなぐった感じなので読みにくい・・・。
1. 何かのaccountからserializerとってきてserialize
2. 適当なshared resourcesにアクセス
3. 2から必要とするaccountを調べて、そこからserializerをとってきて、serialize
このとき、1のaccountより3のaccountの方が番号が若ければDead Lockに持ち込めると思うんだけど、そもそも1と2の順番を入れ替えて、serializeのタイミングをずらすだけで、問題が解決しちゃう場合がある。(ようするに3でaccount得た後に、1と3を比べて、番号が若い順にserializeを行うみたいな)
つまり、1→2の順番であるには、2での操作以降で1のaccountを変更されたくないのでserializeする・・・といったシナリオでないといけないはず。
ということで、考えたのは
a. 1のaccountに別のアカウントの情報があって、そのアカウントに入金しないといけない。(その情報を変更させないためにも1でserializeしないといけない)
b. 1のaccountのbalanceの値と他のaccountのbalanceの値を比べて、その結果から1のaccountとのexchangeの対象を探す。
(途中で1のbalanceが変わるとまずいのでserializeがいる)
とか考えたけど
aだと、そもそもmake-account自体に変更がいるし、まずなぜそんなことをしないといけないかが思い浮かばない・・・。
bだと、「というか比較対象のaccountを全部serializeすればよくね?」
というかんじでハマった…。さぱーりすぐる。