sicp-ex-3.48



<< Previous exercise (3.47) | Index | Next exercise (3.49) >>


gws

  
  
  
 (define (serialized-exchange account1 account2) 
   (let ((serializer1 'serializer-for-bigger-id--acc) 
         (serializer2 'serializer-for-smaller-id-acc)) 
     (cond ((> (get-id account1) (get-id account2)) 
            (set! serializer1 (account1 'serializer)) 
            (set! serializer2 (account2 'serializer))) 
           (else (set! serializer1 (account2 'serializer)) 
                 (set! serializer2 (account1 'serializer)))) 
     ((serializer1 (serializer2 exchange)) account1 account2))) 
  

leafac

This works because it makes impossible for one process to have acquired the lock for a resource A and be waiting for a lock for a resource B while other process has the lock for the resource B and is waiting for a lock for the resource A.

A complete solution that also implements the necessary modifications to make-account-and-serializer and avoids using state:

 (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 'id) id) 
             ((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)) 
  
 (define (serialized-exchange account1 account2) 
   (let* ((serializer1 (account1 'serializer)) 
          (serializer2 (account2 'serializer)) 
          (exchanger (if (< (account1 'id) (account2 'id)) 
                         (serializer1 (serializer2 exchange)) 
                         (serializer2 (serializer1 exchange))))) 
     (exchanger account1 account2)))