There is a simple code:
TParallel.For(1, 8,
procedure(i: Integer)
var
localstr: String;
Data: String;
index: Integer;
begin
Data := 'test1 test2';
index := 0;
while true do
begin
index := index + 1;
localstr := copy(Data, index, 1);
if index > 2 then
index := 0;
end;
end);
It should use 8 CPU cores but it only uses 1. The reason is the system procedure for clearing a string variable:
function _UStrClr(var S): Pointer;
if AtomicDecrement(P.refCnt) = 0 then
FreeMem(P);
AtomicDecrement() applies a lock to make sure that the string's reference count is not simultaneously decremented on different threads. But, I am absolutely sure that my strings are isolated inside the threads. Is there any way to tell TParallel not to do that?
I could use the classic low-level WinAPI calls, but that would lose the legacy code base.
Just because you are creating 8 parallel loop iterations does not guarantee that each iteration will run on its own CPU core. It is entirely possible that some will run on the same CPU core and the OS will have to task-switch between them. Which CPU core a task runs on is up to the OS's thread scheduler.
Your use of the strings is isolated, but the compiler/RTL's use of the strings is not. The underlying memory management is fairly thread-safe, and that means synchronizing access to a string's internal structure, in case multiple threads try to access a given string at the same time.
No, and it is not
TParallel's fault to begin with. This is just how the RTL's internal management ofstrings is implemented in general. If you don't like it, don't use reference-countedstrings to begin with.