更快的TMultiReadExclusiveWriteSynchronizer?

Ian*_*oyd 22 delphi multithreading critical-section readerwriterlock readerwriterlockslim

那里有更快的那种TMultiReadExclusiveWriteSynchronizer吗?FastCode也许吧?

从Windows Vista开始,Microsoft添加了Slim Reader/Writer锁.它的性能比Delphi 好得多TMultiReadExclusiveWriteSynchronizer.不幸的是,它只存在于Windows Vista及更高版本中,这是很少有客户真正拥有的东西.

据推测,Slim Reader/Writer lock在本机中使用的概念可以在本机Delphi代码中重做 - 但有人做过吗?

我有一种情况,即获取和释放锁定TMultiReadExclusiveWriteSynchronizer(即使没有争用 - 单个线程),导致100%的开销(操作时间加倍).我可以在没有锁定的情况下运行,但是我的类不再是线程安全的.

有更快的TMultiReadExclusiveWriteSynchronizer吗?

注意:如果我使用TCriticalSectioni,只会遭受2%的性能损失(尽管已知关键部分在获取成功时很快,即它是单线程并且没有争用).CS的缺点是我失去了" 多个读者 "的能力.

测量

使用TMultiReadExclusiveWriteSynchronizer相当长的时间在内部BeginReadEndRead:

在此输入图像描述

然后移植代码以使用Window自己的SlimReaderWriter Lock(其中一些代码重写,因为它不支持递归锁定),并分析了resutls:

  • TMultiReadExclusiveWriteSynchronizer:每次迭代
    10,698 ns 10,697,772,613 ns,迭代1,000,000次

  • SRWLock:每次迭代
    8,802 ns,8,801,678,339 ns,迭代1,000,000次

  • Omni Reader-Writer lock:每次迭代8,941 ns,
    8,940,552,487 ns,迭代1,000,000次

使用SRWLocks(又名Omni的旋转锁)时,性能提高了17%.

现在,我不能永久地切换代码以使用Windows Vista SRWLocks,因为有些客户仍然在Windows XP上.

Slim锁只是小心使用InterlockedCompareExchange功能; 但比我能成功使用更加小心.我这个远离刚刚偷涉及的140个机器指令,并完成它.

奖金阅读

Edw*_*Yip 6

TOmniMREWOmniThreadLibrary声称更快,更轻量级:

OTL是一个优秀的线程库,BTW.

示例代码

TOmniReaderWriterLock = class(TInterfacedObject, IReaderWriterLock)
private
   omrewReference: Integer;
public
   { IReaderWriterLock }
   procedure BeginRead;
   procedure EndRead;
   procedure BeginWrite;
   procedure EndWrite;
end;

{ TOmniReaderWriterLock }

procedure TOmniReaderWriterLock.BeginRead;
var
  currentReference: Integer;
begin
    //Wait on writer to reset write flag so Reference.Bit0 must be 0 than increase Reference
    repeat
        currentReference := Integer(omrewReference) and not 1;
    until currentReference = Integer(InterlockedCompareExchange(Pointer(omrewReference), Pointer(Integer(currentReference) + 2), Pointer(currentReference)));
end;

procedure TOmniReaderWriterLock.EndRead;
begin
    //Decrease omrewReference
    InterlockedExchangeAdd(@omrewReference, -2);
end;

procedure TOmniReaderWriterLock.BeginWrite;
var
    currentReference: integer;
begin
    //Wait on writer to reset write flag so omrewReference.Bit0 must be 0 then set omrewReference.Bit0
    repeat
        currentReference := omrewReference and (not 1);
    until currentReference = Integer(InterlockedCompareExchange(Pointer(omrewReference), Pointer(currentReference+1), Pointer(currentReference)));

    //Now wait on all readers
    repeat
    until omrewReference = 1;
end;

procedure TOmniReaderWriterLock.EndWrite;
begin
    omrewReference := 0;
end;
Run Code Online (Sandbox Code Playgroud)