不,這些技巧不是線程安全的。 Const
阻止了add-ref,所以由另一個線程所做的更改將以不可預知的方式影響該值。示例程序,嘗試在P
定義改變const
:
{$apptype console}
uses SysUtils, Classes, SyncObjs;
type
TObj = class
public
S: string;
end;
TWorker = class(TThread)
public
procedure Execute; override;
end;
var
lock: TCriticalSection;
obj: TObj;
procedure P(const x: string);
// procedure P(x: string);
begin
Writeln('P(1): x = ', x);
Writeln('Releasing obj');
lock.Release;
Sleep(10); // give worker a chance to run
Writeln('P(2): x = ', x);
end;
procedure TWorker.Execute;
begin
// wait until TMonitor is freed up
Writeln('Worker started...');
lock.Acquire;
Writeln('worker fiddling with obj.S');
obj.S := 'bar';
TMonitor.Exit(obj);
end;
procedure Go;
begin
lock := TCriticalSection.Create;
obj := TObj.Create;
obj.S := 'foo';
UniqueString(obj.S);
lock.Acquire;
TWorker.Create(False);
Sleep(10); // give worker a chance to run and block
P(obj.S);
end;
begin
Go;
end.
但它並不僅僅限於線程;修改的基本變量的位置也有類似的效果:
{$apptype console}
uses SysUtils, Classes, SyncObjs;
type
TObj = class
public
S: string;
end;
var
obj: TObj;
procedure P(const x: string);
begin
Writeln('P(1): x = ', x);
obj.S := 'bar';
Writeln('P(2): x = ', x);
end;
procedure Go;
begin
obj := TObj.Create;
obj.S := 'foo';
UniqueString(obj.S);
P(obj.S);
end;
begin
Go;
end.
如果引用計數在另一個線程中變爲零,則引用計數以錯誤開始。如果兩段代碼都可以修改相同的字符串,那麼字符串的引用計數應該大於1,因爲有明確的多種方式來引用該字符串。每個線程應該有自己的獨立變量來判斷字符串,否則應該使用通常的同步技術來保護共享變量。 – 2011-05-02 02:43:44
非常好的問題。我今天學到了東西。 – 2011-05-02 20:50:36