用于非阻塞多线程同步的无锁,无等待和等待自由算法

时间:2009-09-21 08:52:25

标签: multithreading delphi synchronization delphi-2007

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

究竟我们可以说某些算法是:

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

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

  1. 算法预测此例程的最长执行时间。
  2. 在开始时调用此例程的线程设置唯一引用(在此例程内)。
  3. 调用相同例程的其他线程检查此引用,如果设置的话,则计算第一个涉及的线程的CPU滴答计数(测量时间)。如果该时间是长时间中断当前涉及的线程的工作并覆盖他的工作。
  4. 由于在任务调度程序中被中断(在最后处置)而未完成作业的线程检查引用(如果不属于他)再次重复该作业。
  5. 所以这个算法实际上不是无锁的,但是没有使用内存锁,其他涉及的线程可以等到(或不)某个时间,然后再覆盖重置线程的工作。

    添加 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

2 个答案:

答案 0 :(得分:1)

(我正在回答这个问题,假设它是一个家庭作业问题,如果不是,请提供你所遇问题的更多细节)

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

答案 1 :(得分:1)

我会在这方面工作,虽然没有经过正式培训,并且真的不在乎它是否是作业,因为操作要求确定“什么算法”对我来说(作为海报框架的工作)是“没有等待陈述“涉及执行元组的编程 - 正是系统编程必须解决的问题

  1. 1)算法预测最大值 这个例程的执行时间。
  2. 必须确定数据集大小以及应用于数据集的数据结构的“O”。这可能涉及“堕落的案件”(人们没有计划的事情),这些案件在无法预料的时刻造成破坏。因此,如果没有进一步的细节,人们会选择一种已知故障模式的良好“一般案例”方法,并且在没有“周末毁了”的情况下恢复。罗伯特塞奇威克拥有我能够取得任何进展的最先进的工作 - 工作非常清楚写下你提出的问题。

    1. 2)调用此例程的线程 什么开始设置唯一参考 意味着在这个例行程序中。
    2. 这里有一些语言障碍,但我猜你要问的是代码执行路径(指令序列)以对其数据集的“唯一”“引用”开始 - 因此,唯一的引用意味着 - 所以我们只是重新阅读标准词典中的定义。 (不打算陈腐,这就是我在这里看到的)

      1. 3)正在调用的其他线程 同样的例程检查这个 引用和if设置比count CPU的滴答计数(测量时间) 首先涉及线程。如果那个时候 是长时间中断电流 参与线程的工作和 压倒他的工作。
      2. 参考计数。精心研究 - 只需继续阅读和编码。解决它。中断过期的线程完成充满了看不见的失败模式。说实话,进行实际调度(线程或进程)只能在设计用于容纳该任务的硬件中正确完成。您的“装配优化”帖子可以在可以完成此操作的级别上工作。我建议研究“AVL”零页面算法。在某些时候,处理器和执行调度的指令序列 - 通过问题的定义 - 需要获得某些值的独占锁定 - &gt;通常的技巧是不要让两个线程试图获得两个项目来锁定而不受另一个指令指针的干扰。

        这可能很有挑战性,尤其是当非程序员对编程工作室有权限时 - >这一次又一次导致了灾难。

        1. 4)未完成作业的线程 因为被任务中断了 调度程序(最后安置) 如果不属于,请检查参考 他再次重复这份工作。
        2. 这是调度程序的任务。