【问题标题】:Lock-Free, Wait-Free and Wait-freedom algorithms for non-blocking multi-thread synchronization用于非阻塞多线程同步的无锁、无等待和无等待算法
【发布时间】:2009-09-21 08:52:25
【问题描述】:

在多线程编程中,我们可以找到两个或多个线程/任务之间数据传输同步的不同术语。

什么时候我们可以说某个算法是:

1)Lock-Free
2)Wait-Free
3)Wait-Freedom

我明白无锁是什么意思,但是当我们可以说某些同步算法是无等待或无等待时? 我为多线程同步制作了一些代码(环形缓冲区),它使用无锁方法,但是:

  1. 算法预测此例程的最长执行时间。
  2. 一开始调用此例程的线程设置唯一引用,(在此例程内部)。
  3. 调用同一例程的其他线程检查此引用,如果它设置为计数第一个相关线程的 CPU 滴答计数(测量时间)。如果那个时间要长时间中断所涉及线程的当前工作并覆盖他的工作。
  4. 由于任务调度程序中断(被重新放置)而未完成作业的线程最后检查引用是否不属于他,再次重复作业。

所以这个算法并不是真正的无锁算法,但没有使用内存锁,其他涉及的线程可以等待(或不等待)一定时间,然后覆盖被重新定位的线程的工作。

新增RingBuffer.InsertLeft功能:

function TgjRingBuffer.InsertLeft(const link: pointer): integer;
var
  AtStartReference: cardinal;
  CPUTimeStamp    : int64;
  CurrentLeft     : pointer;
  CurrentReference: cardinal;
  NewLeft         : PReferencedPtr;
  Reference       : cardinal;
label
  TryAgain;
begin
  Reference := GetThreadId + 1;                 //Reference.bit0 := 1
  with rbRingBuffer^ do begin
TryAgain:
    //Set Left.Reference with respect to all other cores :)
    CPUTimeStamp := GetCPUTimeStamp + LoopTicks;
    AtStartReference := Left.Reference OR 1;    //Reference.bit0 := 1
    repeat
      CurrentReference := Left.Reference;
    until (CurrentReference AND 1 = 0)or (GetCPUTimeStamp - CPUTimeStamp > 0);
    //No threads present in ring buffer or current thread timeout
    if ((CurrentReference AND 1 <> 0) and (AtStartReference <> CurrentReference)) or
      not CAS32(CurrentReference, Reference, Left.Reference) then
      goto TryAgain;
    //Calculate RingBuffer NewLeft address
    CurrentLeft := Left.Link;
    NewLeft := pointer(cardinal(CurrentLeft) - SizeOf(TReferencedPtr));
    if cardinal(NewLeft) < cardinal(@Buffer) then
      NewLeft := EndBuffer;
    //Calcolate distance
    result := integer(Right.Link) - Integer(NewLeft);
    //Check buffer full
    if result = 0 then                  //Clear Reference if task still own reference
      if CAS32(Reference, 0, Left.Reference) then
        Exit else
        goto TryAgain;
    //Set NewLeft.Reference
    NewLeft^.Reference := Reference;
    SFence;
    //Try to set link and try to exchange NewLeft and clear Reference if task own reference
    if (Reference <> Left.Reference) or
      not CAS64(NewLeft^.Link, Reference, link, Reference, NewLeft^) or
      not CAS64(CurrentLeft, Reference, NewLeft, 0, Left) then
      goto TryAgain;
    //Calcolate result
    if result < 0 then
      result := Length - integer(cardinal(not Result) div SizeOf(TReferencedPtr)) else
      result := cardinal(result) div SizeOf(TReferencedPtr);
  end; //with
end; { TgjRingBuffer.InsertLeft }

你可以在这里找到RingBuffer单元:RingBuffer,CAS函数:FockFreePrimitives,测试程序:RingBufferFlowTest

【问题讨论】:

  • 这看起来像是一道作业题。如果是,您应该将其标记为作业。人们会帮助你,但不会给你完整的答案,这样你就可以自己学习一些东西。如果这不是家庭作业问题,您应该描述您正在尝试做什么以及您遇到问题的部分。
  • 谢谢西蒙。我已经记下了更多细节。
  • 那么,到底有什么问题呢?
  • 如何确定所描述的程序逻辑的算法类型。
  • @SimonPStevens,homework 标签已被禁用,因此无法标记任何东西 homework

标签: multithreading delphi synchronization delphi-2007


【解决方案1】:

(我基于这是一个家庭作业问题的假设来回答这个问题,如果不是,请提供您遇到的问题的更多详细信息)

您应该开始阅读Non-blocking synchronization 上的维基百科文章。这提供了一些很好的背景信息和您提到的术语的一些定义。

【讨论】:

    【解决方案2】:

    我会努力解决这个问题,虽然没有经过正式培训并且真的不在乎这是否是家庭作业,因为操作要求的是确定“什么算法”对我来说(作为海报框架工作)是“不等涉及执行元组的“状态”编程——正是系统编程必须解决的那种事情

    1. 1) 算法预测最大值 该例程的执行时间。

    必须确定数据集大小以及应用于数据集的数据结构的“O”。这可能涉及在意想不到的时刻造成严重破坏的“退化案例”(人们没有计划的事情)。因此,在没有更多细节的情况下,人们会选择一种好的“一般情况”方法,该方法已知故障模式,并且不会“破坏周末”而恢复罗伯特塞奇威克的工作是我能够取得任何进展的最先进的工作 - 工作非常清楚书面解决您提出的问题。

    1. 2) 调用此例程的线程 开始设置唯一参考,什么 表示这是在这个例程中。

    这里有一些语言障碍,但我猜你要问的是代码执行路径(指令序列)以对其数据集的“唯一”“引用”开始 - 因此,唯一引用意味着 -所以我们只是重新阅读标准词典中的定义。 (无意陈词滥调,这就是我在这里看到的)

    1. 3) 正在调用的其他线程 同样的例程检查这个 参考和如果设置比计数 CPU 滴答计数(测量时间) 第一个涉及的线程。如果那个时候 就是要长打断电流 涉及线程的工作和 压倒他的工作。

    引用计数。好好研究 - 继续阅读和编码。解决它。中断一个过期的线程完成充满了看不见的失败模式。说实话,真正的调度(线程或进程)只有在旨在适应该任务的硬件中才能正确完成。您的“装配优化”帖子的工作水平可以做到这一点。我建议研究“AVL”零页算法。在某些时候,处理器和执行调度的指令序列将 - 根据问题的定义 - 需要获得对某个值的排他锁定 -> 通常的技巧是不要让两个线程尝试获得两个要锁定的项目在不受另一个指令指针干扰的情况下。

    这可能具有挑战性,尤其是当非程序员对编程商店拥有权限时 -> 这会一次又一次地导致灾难。

    1. 4) 未完成工作的线程 因为被任务打断了 调度程序(被搁置)在最后 如果不属于,请检查参考 让他再重复一遍。

    这是调度器的任务。

    【讨论】:

    • Ammm... 我在问 RingBuffer 类型的算法。实际上我的环形缓冲区代码是现实的(免费的)并且运行良好!因此您可以检查或测试程序结构。如果帮助某人获得项目其余部分的链接,我可以为 TgjRingBuffer.InsertLeft 写下部分代码示例。
    • 假设您非常专注于完成您似乎正在做的工作,您正在使用我不熟悉的混合前端编写 -> 可以编写多种类型的代码语言,我看不出到底是什么算法有很大的区别(只要它有效——你说它有效,这对我来说已经足够好了)重要的是我所说的。由于优先级倒置之类的事情,许多伟大的项目都被毁掉了。如果您想测试算法,您可以使用哪些随机生成器来生成测试数据?
    • @Nicholas Jordan 询问“您可以使用哪些随机生成器来生成测试数据?”对于测试,我使用了 16 个作者和 16 个读者线程以及大约 8 小时的测试时间(过夜)。此类测试产生大约 2 * 10^10 次入队/出队检查调用。
    • 好的,我们有一个很好的合作基础,但我只能说(我一直在思考这个问题并深入研究这个问题)是这些数字看起来你有很好的表现它是。我正在伸出脖子,但我一次又一次地看到编译器科学可以完全击败所有合理的调查。唯一实际的解决方案是编写尽可能多的算法并对其进行测试——我们被算法复杂性的复杂讨论所淹没,但编译器和处理器实际所做的一切都被淹没了。只需对其进行破坏测试即可。
    猜你喜欢
    • 2016-10-11
    • 1970-01-01
    • 2022-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-11
    • 2021-12-12
    • 1970-01-01
    相关资源
    最近更新 更多