迪杰斯特拉提出了这个系统命名法。那么,这是执行力量的总和。这个想法很好,但我们仍然需要一些方法来提出相互排斥。信不信由你,只需加载和存储就可以做到这一点。我们稍后会在课堂上讨论这个问题。
但它真的很慢。也就是说,有一些算法只需加载和存储即可完成此操作。但从实施的角度来看,人通常会尝试更快。所以,如果你想加快速度,这可能对你的电脑架构有帮助,你的指令集架构师,想出一个特殊的指令,这将允许你做一些原子的东西。所以,当我们说自己做一些东西时,就意味着在此期间没有别的东西可以交织在一起了。而且,这里的简单解决方案是添加一个可以读取修改和写入的原子操作。所有原子,如果没有其他交错它。所以,回到我们这里的锁和四肢。在这里面,这个P和所有在这里的V都在这里,你需要以某种方式,自动修改S.你需要能够读取S,你需要能够写S,如果你能够用代码实现这个代码P的实现以及V的实现。因此,使得这个速度更快的原语是具有一些读取修改写入操作。我们将看看这个几个不同的选择。
其中最基本的就是测试和设定。 x86有这条指令。这是用于原子操作的x86上最基本的操作之一。许多其他体系结构都有这样做的说明。所以,我们在这里写一段代码。但实际上,这是一段伪代码,但实际上,这是一条指令,我们实际上会相对于系统的其他部分以原子方式执行此操作。那么,让我们看看测试和集合的功能。
测试和设置的基本思想就是它,它可能是你可以做的最原始的原子操作之一。我见过比这更简单的东西。有一个测试和清晰,这是一个更容易实施。但是,很大程度上这个想法是,你将看到一个内存地址。如果这个内存地址是你所期望的,那就写下一些价值。而且,在这段代码中隐含的是,执行测试集的代码片段需要知道它是否被超出,并且能够成功写入值或不写入值。所以,这是一种状态码,它在这里寄存器R中返回。所以,如果我们看看这段代码,就会传入一个内存引用,一个内存地址,它是四个地址或地址锁的地址。你传入它,和一个注册名称。我们对该登记册进行加载并无条件发生。这部分虽然是,但是,是测试部分。所以这里的测试部分是我们检查刚刚从这个内存地址读取的东西是否为零。如果是这样,我们将写一个到内存地址。有时候这些测试和设置操作实际上会让你除了一个之外还写别的东西。
但是,就目前而言,让我们来说,这是一个更基本的方法。所以,它写了一个到那个内存地址。这里重要的是架构保证所有这些都是原子性的。但有趣的是,如果您考虑我们制造的处理器,这需要一个负载和一个存储。嗯。所以,我们将在一些幻灯片中谈论我们如何实现这一点。但是,您基本上必须停止其他一切,停止系统中发生的所有其他负载和存储。做这个加载,做测试,并且可能用硬件做商店。
其中一种更基本的方式是完成这项工作,或者是在一些基于SA-6的架构上实现的原始方式之一,就是在总线上有一种称为锁定位的东西。所以他们所做的就是当一个处理器要执行像这样的原子操作时,例如一个测试集。你实际上会广播系统中的所有其他处理器,说我即将这样做。不要碰任何东西。不要有效地发出任何内存[LAUGH]指令,或不要发出任何总线内存指令。它会执行负载,它会进行测试,然后执行设置,然后释放广播位。这是多点总线上的电线。那是一个相当大的锤子。
从那时起,情况变得更好了。但是,只是为了让你了解这个基本的硬件实现。事情变得更复杂了,这种出现在70年代的这里。这些更奇特的操作或花式的原子操作。所以,这里的整个盒子仍然是一个原子操作。所有的,这里的代码都是原子地发生的,而这个基本的功能就是取得一个内存地址并添加一些内容。所以,我们将R添加到R中,并将它放在内存中,并且以相同的内存地址进行,因此我们将以原子方式在商店中执行加载。所以,这也是一个读取修改的写入操作。拥有一切原子。请注意,这仍然实际返回寄存器R,这里是原始值。
有时候这实际上非常有用,如果你试图在这个基础上实现一个半结构体,你会希望看到之前有什么。虽然有一些,但在这里有一些笑话。原子操作团体在某种程度上将其推向了极端,人们开始在这里获取并插入一些东西。所以,获取和乘法,取和分或者类似的东西,人们开始构建一些有取回和其他东西的陌生机器。这是一个老玩笑,有人打算实现指令fetch和FFT。所以,这将是原子傅立叶变换。我认为它没有达到那一点。但是,在微码日期和早期的微处理器微代码日,有一些非常复杂的原子操作。这在很大程度上决定了不是一个好的方向。你想在原子操作中有一点复杂性。所以测试和设置可能太简单了。但是,这些更好的获取FFT的一些可能有点太复杂。 [COUGH]这是另一个有趣的原子操作。而这个你实际上可以创建一些非常有趣的信号量。它被称为交换。所以,它需要一个寄存器值和一个内存位置,并且它将处理内存位置和寄存器中的内容,并交换两件事情。并且请注意,我们需要使用我们在这里使用的临时文件,因为您不能在没有临时文件的情况下实际交换两件事。这实际上并不常见,因为它很难使用。所以对于比较和交换这种类型的测试和设置以及交换操作之间的事情,有什么比较常见的东西。这就是常用的,我们将在第二时间讨论这个问题。
好吧,现在我们回到我们拥有的多个消费者问题,其中有多个人试图从问答中尝试DQ。让我们介绍一下测试和设置,我们将在这里看看我们的关键部分。我们将使用这个术语互斥体来表示一次只能有一件事进入的四个总和。所以,在这里开始会发生什么呢是一个紧密的循环,这个紧密的循环将从互斥体的重定位读入一个临时寄存器,并将其与零比较。请注意,我们定义了测试并将其设置为如果成功则将其写入内存。所以如果它是零,那意味着它不能实际修改内存。测试失败。所以如果测试失败了,它只会坐在这里旋转。我们称之为忙碌的等待或旋转的自旋螺旋锁,这就是所谓的。如果它获得了锁定,这个读取值就是一个值。所以,如果存在的话,如果它通过,你刚才写的获得了锁定,如果它是一个,它就是零,这不等于或者说不好。好的,抱歉我们做错了。
如果内存地址是a,如果它是一个进入这里的地址,那意味着别人已经锁定了它。如果这是一个零进入这里,这意味着没有人锁定它,但我们现在锁定它并将其设置为一个。所以如果我们获得了锁定,我们会自动将它设置为一个,我们将读取一个零。所以,我们将进入我们的关键部分,并开始执行我们的关键部分。而且,在关键部分,我们可以做店面,我们可以做负荷,我们可以做我们想做的任何事情,因为我们保证没有其他操作,没有其他处理器,没有其他线程正在做任何事情。然后在某个时候,我们需要在这里发布。而且我们实际上不需要测试并设置,我们只需要一个商店。一个商店只是要在真实的位置清除它,而其他一些线程可以安全地进入并且落入关键部分。好的。所以,这可以通过很多不同的实现来完成。我们在这里展示了测试和设置,但这可以通过交换完成,可以通过提取和添加来完成。代码变得更复杂一点。
但是,其中一个有趣的问题是,你是什么,如果你在某种威胁下运行获取关键信息或者获得法律落入关键部分会发生什么,并且假设,终止或被换出很长一段时间时间? [声音]什么,这里会发生什么? [声音]好,系统崩溃。我的意思是,我们,我们在这里没有提到糟糕的记忆。这更多,更多是一个悬念。所以,它会冻结。因此,如果您看起来像非抢先式操作系统,那么这在旧的中很常见。
因此,在Mac OS成为Mac OSX之前,像原来的Mac OS一样,所有版本的排序都是9以及更早的版本。这是一个合作的操作系统。如果有人去抓锁,然后死亡或出错,整个机器会崩溃,崩溃。如果你是先发制人的,我的意思是,有一个计时器关闭,可能你仍然无法取得进展。但至少,操作系统可能会打断你的过程并尝试做一些事情。它可以检测到一个进程被挂起。但是在一个合作的多线程环境中,如果有一个进程,比如说只是处理器,并且永远不会退回处理器或者死掉,而且还有其他进程,也就是说,哪个,哪个,或者说,你抓住了锁和一个进程并死亡。然后,另一个过程正在奔跑并试图获得锁定,但它只是坐在这里旋转在这个小旋转部分永远。你基本上只是要挂处理器。你不会在这里看到其他的东西。所以,你必须非常小心,特别是在协作式多线程环境中。所以,其中一个诀窍实际上是,如果你处于一个合作的多线程环境中,他们通常会把这个东西放在旋转循环里面,这会产生一个不同的线程。所以,别人可以尝试在那个时候做点什么。因为如果你坐在那里旋转,很可能你会不公平,或者其他人无法解锁。所以,你必须在那里小心一点。好的。
所以,我们要在这里前进。并看看如何做一个相同的代码片略有不同的版本,但现在与比较和交换。所以,在我们这样做之前,我们来谈谈比较和交换的语义。比较和交换在这里占用内存和两个寄存器。它将比较内存和其中一个寄存器。如果它是平等的,那么它将采取另一个寄存器,把它放在内存中,并有效地交换它们以换取状态。如果比较操作失败,并且我们来到这个L台语句,我们不做任何交换。所以这将有效地取得一个寄存器和一个存储器位置并交换它们,这取决于另一个寄存器。所以,它比交换更强大一点。正如你想象的那样,实施起来有点困难。它可能不像获取和应用程序那样很难实现。原因是,如果你想从内存系统中完成这个操作,你可以基本上把它作为原子操作来发送。转到主内存,比较这个,把一个比较器放在那里,交换两个东西。如果您尝试使用这些增量或任意指令或添加,您需要将加法器放在那里。这只需要一个比较器。仍然,还是,执行器还是很痛苦。但是,它可能比在内存控制器中放置一个完整的加法器好一点,因为这几乎就像在内存子系统中复制ALU一样,这并没有什么意义。但是,这就是为什么人们习惯谈论获取FFT的原因。
但是,好的。所以,让我们来看看这个多阅读器代码片段的同一个案例。但相反,我们要做的就是在开始时我们不会有旋转锁定。相反,我们将会有一个关键部分,但是我们可以同时执行来自不同线程的关键部分,我们现在不会将其称为关键部分。我们将要说,我们将同时执行另一个线程的关键部分中的内容,然后我们将自动尝试换出头指针并将其替换。所以,我们正在这里进行投机性工作,这被称为非阻塞式,非阻塞式同步。所以,同步原语我们要做的负载,我们之前讨论过。我们检查确认至少有一些可用的东西。 [COUGH]我们将拉开头指针。这一切都是推测性的工作,因为我们没有检查以确保我们能够有效地拉开队列头。我们将把头指针增加到一个临时的位置,我们将调用新头或注册新头。然后,我们要做一个,尝试用原子交换新头与旧头。所以,我们认为这个寄存器是头指针所在的新头和内存位置。我们将尝试交换这两件事。而我们在这里依赖的是我们认为是老头,还是老头。 [声音]如果这里发生了不好的事情,我们可以,我们可以再试一次。所以,这里的想法是,我们要在这个有效的更大的循环中实际旋转,试图推测性地尝试去改变头部。 [SOUND]所以,这里出现的一个问题是,如果头部是DQ#39;d的,又加了回来,而且恰恰我们有某种形式,这就是所谓的ABA问题呢?在这短暂的时间内,头部指针是a,变成了,后来又变回了a。
是啊。那在这段代码中这可能是一个问题。您可能需要仔细考虑并仔细考虑。通常情况下,你可以用其他方式来保护它,例如,当指针环绕时,也许。如果你想到一个正常的光线,当它环绕时,你把一些不是比较和交换的东西。你可以像更多的自旋锁或者旋转循环类的锁一样。所以,当这些循环缓冲区出现问题时,您只需要担心这种情况。因为不然的话,没有其他的方式,头指针可以回到之前的位置。但是,你确实需要担心这一点,你在这个非常短的时间内围绕阵列打包。
所以,有一些,如果这些非阻塞同步操作发生了一些竞争条件。另一个实际上非常酷的非阻塞同步原语,我认为有很多不同的名字。它通过加载锁定,加载链接,加载预留和存储条件进行。所以,你把你的ISA,你的指令集,并添加两个新的说明。检查以确保某件东西没有加载,然后你做的是存储有条件检查以确保没有其他人执行加载。或者在会议间的时间内使用同一地址的特殊负载链接。我可以再解释一次,这有点令人困惑。但是,基本上这个想法是在这里登记的。在硬件中,你做一个负载链接。只需将该值加载到寄存器中,并将其加载到寄存器旁边的某个位置。它可能不是架构上可见的,或者不应该是架构上可见的。它会设置一点。你执行你的关键部分。当你回到它的时候,去做商店,我们说,这种读取修改后的写入操作。当你去商店时,商店会检查以确定该标志仍然被设置为1。国旗是一个。如果它仍然是一个,那就意味着没有人对该地址做过任何记忆,记忆操作,或者至少没有任何负载链接或在会间时间内将该地址的首字母存储到该地址。其实,对不起。我们会更完整地说。在那段时间内没有其他人做过有条件的商店。所以,没有人试图进行商店更新。其他人可能试图做一个负载。但是,没有其他人能够在该地址存储,或者在该地址存储有条件的地址。因为如果其他人进行有条件的存储,将会发生的是它实际上会取消另一个处理器的预留,因此将它们的标志位设置为零。这是一个非常原始的东西,这是一个非常强大的原始语言,你可以基本上做一个负载。尽量在将来再做一家商店。如果没有其他人尝试在此期间向同一地址做商店,或者在此期间有条件访问该地址的商店,则您的商店会经过并与其他人一起加载。如果他们在此期间进行加载,将会失效,或者他们会知道当他们去做有条件的商店时它会失效。
因此,如果我们在这里采用相同的示例,并且我们使用负载链接和条件存储来实现,那么我们将在这里查看通常进行更新的头指针。我们将会对这个寄存器进行加载。而且,当我们进入有条件的商店时,如果我们,其他人在此期间更改了此值,我们将会失败,并且我们将跳回来并重新加载负载链接。而且这实际上也摆脱了ABA问题。因为如果你确实有这种种族的话,其他人就会为该地址做一个条件限制,并且将所有这些东西都包装起来,甚至可以在那一点上验证你的标志,如果你愿意的话。我们正在标记该内存地址。人们喜欢这样做的一个原因是,当你在商店有条件的地方进行加载链接或加载预留时,你可以通过内存一致性协议很多次地捎带它。这样,你做一个负载链接,它会在你的记忆中增加一点点,我们会说。所以,如果你正在做某种内存一致性协议,它会把它放到缓存中,你可以将这个小循环线标记为特殊的,或者这里的标志位是有效的,因为整行是负载链接的。
然后,如果没有其他人将其从缓存中推出或在缓存中取回,那么就意味着没有其他人在其上执行加载链接。到你去商店的时候,你知道没
全文共9439字,剩余内容已隐藏,支付完成后下载完整资料
资料编号:[12356],资料为PDF文档或Word文档,PDF文档可免费转换为Word
以上是毕业论文外文翻译,课题毕业论文、任务书、文献综述、开题报告、程序设计、图纸设计等资料可联系客服协助查找。