如果源数组位于只读集合中,该集合只能在COW (复制上写)操作后才能更改,
是一种克隆字符串数组的安全方法吗?
for i:= Low(Source) to High(Source) do begin
InterlockedIncStringRefCount(@Source[a]);
end;
Move(Source[0], Dest[0], Size * SizeOf(string));下面是一个示例应用程序来查看克隆的运行情况。
辅助移动速度是System.CopyArray的两倍。
如果我取消增量的联锁,速度会再次翻倍(但是我需要在复制时锁定数组,这可能会花费更多)。
program Project10;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
System.Math
//,FastMove
;
const
Size = 100 * 1000;
function RDTSC: Int64;
asm
RDTSC;
end;
procedure InterlockedIncStringRefCount(p: pointer);
asm
mov eax,[eax]
test eax,eax
jz @done
mov ecx,[eax-8]
inc ecx
jz @done //Do not touch constant strings.
lock inc dword ptr[eax-8];
@done:
end;
var
Source: array[0..Size] of string;
Dest: array of string;
i,a: Integer;
StartTime: Int64;
Duration, MinDuration: Int64;
begin
for i:= 0 to Size do begin
Source[i]:= IntToStr(i);
end;
SetLength(Dest, Size);
//Assisted move
MinDuration:= MaxInt;
for i:= 0 to 100 do begin
StartTime:= RDTSC;
for a:= 0 to Size-1 do begin
InterlockedIncStringRefCount(@Source[a]);
end;
{FastMove.}Move(Source[0], Dest[0], Size * SizeOf(string));
Duration:= RDTSC - StartTime;
MinDuration:= Min(Duration, MinDuration);
end;
Writeln('Assisted move took '+IntToStr(MinDuration div 1000)+' ticks');
Readln;
end.发布于 2014-09-03 16:41:23
由于提到Source是只读的,这段代码是线程安全的.它所做的与系统单元实现字符串分配的工作本质上是相同的,只不过代码通过Move批量复制引用,而不是单独复制每个字符串引用。
您提到了锁定Source,然后在没有互锁操作的情况下递增引用计数的替代方案。那就错了。锁定Source不会做任何事情,因为这不是正在改变的事情。下面是一个例子:
假设线程1正在调用这个数组复制代码,从Dest1生成Source。还假设线程2已经以同样的方式生成了Dest2。这意味着Source[0]和Dest2[0]都引用相同的单个字符串。现在假设线程2运行Dest2[0] := ''以清除其数组的第一个元素。这将减少字符串的引用计数,而不会受到线程1操作的任何保护。如果线程1在线程2修改字符串的同时使用非互锁操作修改该字符串的引用计数,那么您就有了竞争条件。线程1锁定了对Source的访问,这与此无关,因为线程2没有对Source进行操作。它只对Source引用的字符串执行操作。
https://stackoverflow.com/questions/25645802
复制相似问题