Ben 的程序并不安全,而且会阻止单一对象进行并发。
考虑原本未修改的 make-account
程序,如果执行以下的求值序列的话,那么所有表达式都会被放进串行化组 protected
当中,其中每个操作符都是一个 protected
的串行化实例:
((protected withdraw) 10)
((protected withdraw) 20)
((protected withdraw) 30)
((protected withdraw) 40)
现在,想想使用 Ben 的 make-account
执行上面的求值序列会发生什么事情:它会用同一个 protected-withdraw
串行化对象处理所有调用请求:
(protected-withdraw 10)
(protected-withdraw 20)
(protected-withdraw 30)
(protected-withdraw 40)
假设解释器正在处理 (protected-withdraw 10)
,这时其他三个表达式也开始并发地运行,那么除了 (protected-withdraw 10)
之外,其他三个表达式都会出错,因为运行中的串行化进程是不能被其他过程所干扰的。
如果对 (protected withdraw)
和 protected-withdraw
在环境图上进行对比,就会发现很明显的区别。
以下是未修改的 make-account
执行指定的调用序列时产生的环境图:
...
^
|
+---------------------------------------------------------------------------------------------------------------+
| |
| protected |
| |
+---------------------------------------------------------------------------------------------------------------+
| | | |
| ((protected withdraw) | ((protected withdraw) | ((protected withdraw) | ((protected withdraw)
| 10) | 20) | 30) | 40)
| | | |
v v v v
+----------------+ +----------------+ +----------------+ +----------------+
| | | | | | | |
| 串行化地运行着 | | 串行化地运行着 | | 串行化地运行着 | | 串行化地运行着 |
| (withdraw 10) | | (withdraw 20) | | (withdraw 30) | | (withdraw 40) |
| | | | | | | |
+----------------+ +----------------+ +----------------+ +----------------+
以下是 Ben 修改的 make-account
执行指定的调用序列时产生的环境图:
+-------------------------+
| |
| protected |
| |
+-------------------------+
^
|
|
失败 +-------------------------+
(protected-withdraw 20)\<--------------+ | (protected-withdraw 10)
(protected-withdraw 30)+-----------> protected-withdraw <------------------+
(protected-withdraw 40)/ 尝试调用 | protected-deposit | |
| | |
+-------------------------+ |
+----------------+
| |
| 串行化地运行着 |
| (withdraw 10) |
| |
+----------------+