<< Previous exercise (3.41)
| Index |
Next exercise (3.43) >>
A possible test for whether the change proposed here is safe:
(let ((acc (make-account 100)))
(lambda () ((acc 'withdraw) 10))
(lambda () ((acc 'withdraw) 20)))
The original version in book *certainly* returns 70 here, since each of the two withdrawals results in a *separately* serialized procedure. The modified version on the other hand has both withdrawals using a *single* serialized procedure.
Without further knowledge of how make-serial and parallel-execute actually work, it's hard to tell whether a serialized function can be interleaved *with itself*. If yes, then for the modified version, there may be a data race and the above block of code can incorrectly return 90 or 80. If not, then the modified version in this exercise works perfectly.
A reasonable thing to say would be that since both arguments to parallel-execute were serialized using the same serializer (since they are actually the same *function*), we should expect them to not interleave with each other, and hence the modification *should* work.
It's safe to do that change. There is nothing different about concurrency in these two version. The only difference is new one serialize the procedures before call the functions, but the original one do it when call withdraw or deposit.
The original solution and the one proposed by Ben Bitdiddle are essentially the same.
I agree with it's safe to change, but I don't think there is no difference. In changed version, all accounts created share a same serialized set, which means only one account could execute withdraw or deposit at a same time. Hence there will be no concurrency between different accounts.
Every time make-account is called make-serializer is called. There will be a unique serializer for every account. I don't agree that "only one account could execute withdraw or deposit at the same time."