Moh*_*enB 4 delphi thread-safety delphi-xe2
在这段代码中:
TMyClass = class(TThread)
public
FInputBuffer : TThreadedQueue<TBytes>;
protected
procedure Execute; override;
end;
Run Code Online (Sandbox Code Playgroud)
使用(在TMyClass和其他类中)FInputBuffer是线程安全吗?
编辑:
样本使用:在TMyClass中:
procedure TMyClass.Execute;
var x :TBytes;
begin
inherited;
FInputBuffer:= TThreadedQueue<TBytes>.Create;
while not Terminated do begin
if FInputBuffer.QueueSize > 0 then begin
x:= FInputBuffer.PopItem;
//some code to use x
end;
end;
FInputBuffer.Free;
end;
Run Code Online (Sandbox Code Playgroud)
在其他课程:
var MyClass :TMyClass ;
procedure TForm1.btn1Click(Sender: TObject);
var x :TBytes;
begin
//set x
MyClass.FInputBuffer.PushItem(x);
end;
Run Code Online (Sandbox Code Playgroud)
Rem*_*eau 11
如果FInputBuffer是在线程构造函数创建线程之前开始运行,并在线程析构函数释放线程运行完毕,那么,对它的访问从其他线程是线程安全的,而之后TMyClass的对象仍然活着,因为TThreadedQueue提供了内在内容的自身线程安全性.您所展示的是对多线程队列的完全有效使用,前提是该MyClass变量在btn1Click()调用时有效.
但是,如果FInputBuffer是在其中创建的Execute(),那么它不是线程安全的,因为btn1Click()可能会FInputBuffer在创建之前尝试在线程开始运行之前访问队列.这就是你需要FInputBuffer在构造函数中创建的原因,例如:
TMyClass = class(TThread)
public
FInputBuffer: TThreadedQueue<TBytes>;
constructor Create(ACreateSuspended: Boolean); override;
destructor Destroy; override;
protected
procedure Execute; override;
end;
constructor TMyClass.Create(ACreateSuspended: Boolean);
begin
inherited;
FInputBuffer := TThreadedQueue<TBytes>.Create;
end;
destructor TMyClass.Destroy;
begin
FInputBuffer.Free;
inherited;
end;
procedure TMyClass.Execute;
var
x: TBytes;
begin
while not Terminated do begin
if FInputBuffer.QueueSize > 0 then begin
x := FInputBuffer.PopItem;
// some code to use x
end;
end;
end;
Run Code Online (Sandbox Code Playgroud)
如果你想在FInputBuffer里面创建Execute(),那么线程应该暴露一个在FInputBuffer实际创建之后设置的标志/信号,然后FInputBuffer在设置该标志/信号之前没有其他代码应该尝试访问.创建线程实例的代码应该在将控制权返回到代码的其余部分之前等待该标志/信号,例如:
TMyClass = class(TThread)
public
FInputBuffer: TThreadedQueue<TBytes>;
FInputBufferCreated: TEvent;
constructor Create(ACreateSuspended: Boolean); override;
destructor Destroy; override;
protected
procedure Execute; override;
procedure DoTerminate; override;
end;
constructor TMyClass.Create(ACreateSuspended: Boolean);
begin
inherited;
FInputBufferCreated := TEvent.Create(nil, True, False, '');
end;
destructor TMyClass.Destroy;
begin
FInputBufferCreated.Free;
inherited;
end;
procedure TMyClass.Execute;
var
x: TBytes;
begin
FInputBuffer := TThreadedQueue<TBytes>.Create;
FInputBufferCreated.SetEvent;
while not Terminated do begin
if FInputBuffer.QueueSize > 0 then begin
x := FInputBuffer.PopItem;
// some code to use x
end;
end;
end;
procedure TMyClass.DoTerminate;
begin
if FInputBufferCreated <> nil then
FInputBufferCreated.ResetEvent;
FreeAndNil(FInputBuffer);
inherited;
end;
Run Code Online (Sandbox Code Playgroud)
.
var
MyClass: TMyClass = nil;
procedure TForm1.StartBufferThread;
var
I: Integer;
begin
MyClass := TMyClass.Create(False);
if MyClass.FInputBufferCreated.WaitFor(2500) <> wrSignaled then
begin
MyClass.Terminate;
MyClass.WaitFor;
FreeAndNil(MyClass);
raise Exception.Create('MyClass.FInputBuffer not created after 2.5 seconds!');
end;
end;
procedure TForm1.btn1Click(Sender: TObject);
var
x: TBytes;
begin
//set x
if MyClass <> nil then
MyClass.FInputBuffer.PushItem(x);
end;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
301 次 |
| 最近记录: |