关于STM实现的问题
我已经读过两个完全不同的STM如何实现的账户。 也许两个都是有效的,或者有一个是错误的,我希望有人能够发光。
以1 (维基百科):允许所有线程修改共享内存,但事务中的每个读写都被记录下来。 在事务结束时,系统检查其他线程没有同时对内存进行更改。 如果没有进行更改,则交易已完成。 否则,交易重新开始。
以2 (无法找到源代码):当一个程序进入事务处理时,它会得到一个包含在其中的所有变量的副本,并可以在其上进入城市。 在交易结束时,系统尝试用副本更新主设备。 如果自从第一次创建副本后,主服务器没有发生更改,则交易将被提交。 否则,交易重新开始。
另外,当两个线程同时进入同一个事务时会发生什么? 这不会造成种族差异吗? 由于两者都试图修改相同的共享内存,因此两者都需要重新启动,除非系统进入并告诉一个线程冷却它(有点像锁=),否则问题将继续无限。这里错过了一个概念。
我不是专家,但已阅读了几篇论文。 正如新技术的提案一样,看起来像一个小组提出了STM,但其他小组随后的工作研究了各种变化。 你提到的不止两个。 例如,本文提供了一种阻止交易锁定的机制,而不是您的两种攻击性的非阻塞方法:http://pages.cs.wisc.edu/~david/courses/cs758/Fall2007/papers/ saha-mcrt-ppopp-2007.pdf实现技术中唯一通用的线程似乎是数据库类事务语义。 所以研究的核心问题是这些语义是否会导致更好的程序和/或更高的效率。 他们如何实施是抢劫。
另外,当两个线程同时进入同一个事务时会发生什么? 这不会造成种族差异吗? 由于两者都试图修改相同的共享内存,因此都需要重新启动......
不是真的。 系统总是进步,因为当两个或更多的提交发生冲突时,日志允许所有的回滚到冲突事务开始的地方。 然后,可以允许线程继续并按顺序提交。 你说得对,这会导致重复工作,尤其是当单个对象需求量很大时。 但是,只有在比上下文交换更昂贵的情况下,避免这种情况才值得。 STM人士认为,记忆冲突相对较少。 维基百科计划在这个假设中特别具有侵略性。
下面是一个回答链接,概述了TL2 STM算法,它提供了一些关于实现它的相当可读的论文的链接,以及如何将普通代码机械转换为STM代码:
Stackoverflow:你如何实现软件事务内存?
显然它是一个活跃的研究领域,所以有很多方法。 对于一个给定的问题,最适合的问题取决于手头问题的并发性和读/写比。
关于TL2算法你的问题:
......在同一个事务中允许两个线程执行似乎没有用处。 他们将读取彼此的写入,并且事务块内的计算将变得格格不入。
它关于在事务期间看到的数据(读取集)或更新的(写入集),而不是他们正在执行的代码。 TL2算法允许推测性工作发生,没有锁保持写集专用于每个线程直到提交。 在提交时,事务采用写入锁定,然后最终版本检查读取集合版本是否仍然匹配主值版本(公共提交值),然后将更新刷新到主值增加其版本。 当然,事务在提交之前可以看到它自己的私有更新,并且任何提交的主值,但不同的tx不会看到其他每个都不刷新的写入集。 如果某个其他事务同时提交并且改变了从读取集中看到的主版本,则tx被中止。 这可以在应用程序逻辑运行时保持一致性而不需要锁。 上面链接中的论文有更多的细节和优化。
另外,当两个线程同时进入同一个事务时会发生什么? 这不会造成种族差异吗?
如果他们正在读取另一个线程将更新的值,则执行不同工作时,是否与TL2竞争。 由于在最终的一致性检查中中止工作,工作可能会被抛弃。 当发生这种情况时,您应该编码重试很多次,直到获得一致的读取,最终导致成功提交。 我们希望如果你的服务器上有很多核心,你偶尔会把核心的工作抛出去,而不是使用阻塞核心的粒度锁。 另一个希望是,STM可以比手工制作最佳的细粒度锁定方法更直接,避免死锁。 显然,吞吐量取决于实际的应用逻辑和冲突。
由于两者都试图修改相同的共享内存,因此两者都需要重新启动,并且问题将继续无限,除非系统进入并告诉一个线程冷却它(有点像锁=)
通过在提交时锁定主值来避免您提到的活锁。 以主值内存地址的递增内存顺序取出所有锁,并且不会发生死锁。 两个线程中的一个将首先获得所需的所有锁。 另一个会阻止。 然后第一个线程将执行读取集一致性检查,刷新它的写入集,递增主值,然后释放锁。 第二个线程将最终获得所有的锁,然后执行读取集一致性检查,并且由于看到线程已增加其应用程序逻辑中使用的主值的版本而中止事务。
显然,这个提交时间锁定策略会阻塞线程,但在任意应用程序逻辑运行时不会保持锁定。 这个关键部分可以进行深入调整。 这些论文甚至提到了处理器指令,这些指令要求线程在持有这些锁的同时不间断地运行。
链接地址: http://www.djcxy.com/p/81453.html