9

TVar 是如何工作的?从我读过的内容来看,它会在收到它们后立即尝试运行所有事务,但是,完成的事务会使其他当前正在运行的事务无效,然后必须重新启动。TVar 是这样工作的吗?

如果是这种情况,如果每 100 毫秒发生 1 毫秒长的事务,这是否意味着需要 200 毫秒来处理的事务永远不会完成?

4

2 回答 2

10

只要两个事务访问 distinct TVars,它们就可以同时提交而不会相互失效。

为了明确交易何时失效,让我们考虑以下场景:

  1. 假设它在事务开始时t :: TVar Int被初始化0并被读取。readTVar tA
  2. B同时,在另一个线程中,开始执行a的事务writeTVar t 1。假设B之前提交A。STM系统会检查是否有不一致的地方,B判断此时commit是安全的,所以现在writeTVar t 1生效。
  3. 但是,这会导致事务A无效,因为 的旧值0t在 的开头读取的A。(如果A允许提交,我们将违反原子性。)

关于 Haskell 的 STM 系统(参见第 6.5 节)的原始论文 [1] 回答了您的问题:

“饥饿是可能的。例如,运行很长时间的事务可能会反复与较短的事务发生冲突。我们认为在实践中不太可能发生饥饿,但如果没有进一步的经验,我们无法判断。”

[1] 蒂姆·哈里斯、西蒙·马洛、西蒙·佩顿·琼斯和莫里斯·赫利希。ACM 并行编程原理与实践会议 2005 (PPoPP'05)。

于 2012-04-10T16:57:29.810 回答
4

如果每 100 毫秒发生 1 毫秒长的事务,这是否意味着需要 200 毫秒处理的事务永远不会完成?

事务只有在接触相同TVar的 s 时才会发生冲突,所以如果 1ms 事务中的一些避免了 200ms 事务影响的所有变量,那么 200ms 事务将能够完成。此外,由于STMmonad 对内部允许的内容非常严格(仅限内存访问和纯计算!),因此在事务长度之间存在这种差异是非常不寻常的。通常,它们只有几次内存读/写,而且所有的IO其他计算将在事务之外完成。此外,一个特定的事务是否永远被其他事务阻塞是一个调度问题。我不能 100% 确定 GHC 当前的调度程序是什么样子,但它优先考虑旧的(或更高的失败率)事务似乎是合理的。

也就是说,活锁是一个非常现实的问题STM,并且与更传统的锁定并发实现中的死锁一样阴险且难以推理。

TVar 是如何工作的?

你可能会喜欢这篇论文:

于 2012-04-10T16:59:53.623 回答