有关STM实施的问题

时间:2012-05-31 03:10:31

标签: transactions multicore stm

我已经阅读了两个关于如何实现STM的完全不同的说明。也许两者都是有效的,或者一个是错的,我希望有人可以解释。

取1 (维基百科):允许所有线程修改共享内存,但会记录事务中的每次读写操作。在事务结束时,系统检查其他线程是否未同时对内存进行更改。如果未进行任何更改,则提交事务。否则,重新开始交易。

  • 问:如果这是一个有效的implmentation,那么允许两个线程在同一个事务中执行似乎没用。他们会读取彼此的写入,并且事务块中的计算将会出错。

取2 (找不到来源):当一个程序进入交易时,它会得到一个包含在其中的所有变量的副本,并且可以在它们上面进入城镇。在事务结束时,系统尝试使用副本更新主服务器。如果自首次创建副本后主服务器未更改,则提交事务。否则,重新开始交易。

此外,当两个线程同时进入同一个事务时会发生什么?这不会导致各种竞争条件吗?由于两者都试图修改相同的共享内存,所以两者都需要重新启动,问题会无限期地继续,除非系统介入并告诉一个线程冷却它(有点像锁=)我敢肯定我是在这里错过了一个概念。

2 个答案:

答案 0 :(得分:3)

我不是专家,但已经阅读了一些论文。与新技术提案一样,看起来一个小组提出了STM,但其他​​小组的后续工作则考虑了变化。你提到的不仅仅是两个。例如,本文提供了一种机制,它阻止了事务的锁定,而不是你们两个中的积极的非阻塞方法:http://pages.cs.wisc.edu/~david/courses/cs758/Fall2007/papers/saha-mcrt-ppopp-2007.pdf 实现技术中唯一常见的线程似乎是类似数据库的事务语义。因此,研究的核心问题是这些语义是否会带来更好的程序和/或更高的效率。他们如何实施是可以争夺的。

  

此外,当两个线程同时进入同一个事务时会发生什么?这不会导致各种竞争条件吗?由于两者都试图修改相同的共享内存,因此都需要重新启动...

不是真的。系统总是在进行中,因为当两个或多个提交冲突时,日志允许所有内容回滚到冲突事务开始的位置。然后可以允许线程继续并顺序提交。你是对的,这导致重复工作,特别是当一个对象需求量很大时。然而,只有当它比上下文交换更昂贵时,避免这种情况才有价值。 STM人员认为记忆冲突相对较少。维基百科计划在这一假设中特别具有攻击性。

答案 1 :(得分:1)

这是一个答案的链接,其中概述了TL2 STM算法,并提供了一些关于实现它以及如何将正常代码机械转换为STM代码的相当可读的论文的链接:

Stackoverflow: How do you implement Software Transactional Memory?

显然,这是一个活跃的研究领域,所以有很多方法。对于给定问题可能最有效的方法取决于手头问题的并发性和读/写比。

关于TL2算法你的问题:

  

...允许两个线程在同一个线程内执行似乎没用   交易。他们会阅读彼此的写作和计算   交易区内的格式不正确。

关于在事务期间看到的数据(读取集)或更新(写入集),而不是它们正在执行的代码。 TL2算法允许推测工作发生,没有锁定保持写入集对每个线程保密,直到提交。在提交时,事务采用写锁定,然后最终版本检查读取集版本是否仍然匹配主值版本(公共提交值),然后刷新更新为增加其版本的主值。当然,事务可以在提交之前看到自己的私有更新,并且任何已提交的主值,但不同的tx不会看到彼此未刷新的写入集。如果某个其他事务同时已提交并更改了从读取集中看到的主版本,则tx将被中止。这在应用程序逻辑运行时不保持锁定就强制执行一致性。上面链接中的论文有更多的细节和优化。

  

此外,当两个线程进入同一个事务时会发生什么   同时?这不会导致各种竞争条件吗?

是线程在执行不同的工作时与TL2竞争,如果它们正在读取另一个线程将更新的值。由于最终的一致性检查中止,工作可能会被丢弃。在发生这种情况时,您应该编写代码重试多次,直到获得一致的读取,最终导致成功提交。希望如果你的服务器上有很多内核,那么通过使用阻止内核的课程粒度锁来偶尔抛弃核心的工作,你将获得更多的总吞吐量。另一个希望是STM可以比手工制作最佳细粒度锁定方法更直接,避免死锁。显然,吞吐量取决于实际的应用程序逻辑和冲突。

  

由于两者都试图修改相同的共享内存,两者都会   需要重新启动,问题继续无限期,除非   系统介入并告诉一个线程冷却它(有点像锁=)

通过在提交时对主值进行锁定,可以避免提到的活锁。以主值内存地址的升序内存顺序获取所有锁定,您将不会遇到死锁。两个线程中的一个将获得它首先需要的所有锁。另一个会阻止。然后,第一个线程将执行其读取集一致性检查,刷新它的写入集,增加主值,然后释放锁。第二个线程最终将获取它的所有锁,然后执行其读集一致性检查,并由于看到线程1增加了它在其应用程序逻辑中使用的主值的版本而中止事务。

显然,这个提交时锁定策略会阻塞线程,但在任意应用程序逻辑运行时不会保持锁定。这个关键部分可以进行积极的调整。这些论文甚至提到了处理器指令,这些处理器指令要求线程在持有这些锁时不会中断运行。