真正的通勤方式。 (通勤身份功能和价值观)
Clojure文档说:
用法:(通勤ref fun& args)
必须在交易中调用。将ref的in-transaction-value设置为:
(应用有趣的in-transaction-value-of-ref args)并返回ref的in-transaction-value。
在事务的提交点,将ref的值设置为:
(应用最近最具承诺价值的参考作品)
所以通勤形式分两个阶段进行。
是第二阶段原子?(应用最近最具承诺价值的参考args)
如果没有,这个例子中发生了什么: 2个线程(T1和T2)。
两者都会增加(交换功能)相同的身份。
IDENTITY: (def i (ref 0 )
(dosync (commute inc i ) )
通勤呼叫公司第一步中的T1,ref i = 0(交易价值= 1)
T1停止
在通勤呼叫inc的第一步中的T2,其中ref i = 0(在事务值= 1中)
T2停止
第二步中的T1再次调用inc,最近提交值i = 0,inc函数返回但更新前ref(i)T1停止
第二步中的T2再次使用最近的提交值i = 0调用inc并更新引用
T1再次启动并使用inc返回值= 1
更新引用这是竞争条件问题?如何避免这种情况? 如果第二阶段是原子的,那就不会发生。
提前致谢
更新: 如果我理解正确的通勤操作的最后阶段(提交点)是同步的“LOCK通勤乐趣UNLOCK **”?
答案 0 :(得分:5)
关键是要意识到ref的in-transaction值(由通勤产生)实际上可能与最终在提交点写入ref的值不同。
在你的例子中,线程T1和T2同时运行它们的事务,我指的是0.它们(inc i)都是通过通信,因此在它们的事务中都看到i = 1。但是,当它们准备提交时,commute(inc)中指定的函数将使用最近提交的值应用于ref。因此,如果T1先提交,i = 1,则T2提交,i = 2。在回答你的问题时,这些提交确实是原子的,所以没有竞争条件是可能的。
我引用下面的通勤文件:
在事务的提交点,将ref的值设置为:
(apply fun most-recently-committed-value-of-ref args)
因此,乐趣应该是可交换的,或者,如果失败,你必须接受最后一次胜利的行为。
“last-one-in-wins”位警告你,如果你正在应用的函数不可交换 - 想到矩阵乘法 - 那么实际上是竞争条件< em> 可能。即,首先提交的事务将其功能应用于“原始”ref值,并且下一个要提交的事务将其功能应用于更新状态。但是,函数应用程序仍然以原子方式应用。