通勤如何工作?

时间:2010-11-14 20:03:45

标签: concurrency clojure

真正的通勤方式。     (通勤身份功能和价值观)

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 **”?

1 个答案:

答案 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值,并且下一个要提交的事务将其功能应用于更新状态。但是,函数应用程序仍然以原子方式应用。