delphi – TThread本身的线程安全字段是否安全?
发布时间:2020-12-15 09:40:46 所属栏目:大数据 来源:网络整理
导读:在这段代码中: TMyClass = class(TThread)public FInputBuffer : TThreadedQueueTBytes;protected procedure Execute; override;end; 使用(在TMyClass和其他类中)FInputBuffer是线程安全吗? 编辑: 样本使用:在TMyClass中: procedure TMyClass.Execute;v
在这段代码中:
TMyClass = class(TThread) public FInputBuffer : TThreadedQueue<TBytes>; protected procedure Execute; override; end; 使用(在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; 在其他课程: var MyClass :TMyClass ; procedure TForm1.btn1Click(Sender: TObject); var x :TBytes; begin //set x MyClass.FInputBuffer.PushItem(x); end; 解决方法
如果在线程开始运行之前在线程构造函数中创建了FInputBuffer,并且在线程完成运行后在线程析构函数中释放了FInputBuffer,那么是的,当TMyClass对象仍处于活动状态时,从其他线程访问它是线程安全的,因为TThreadedQueue为其内部内容提供了自己的线程安全性.如果MyClass变量在调用btn1Click()时有效,那么您所展示的是完全有效地使用多线程队列.
但是,如果在Execute()内部创建了FInputBuffer,那么它不是线程安全的,因为在创建FInputBuffer之前,btn1Click()可能会在线程开始运行之前尝试访问队列.这就是你需要在构造函数中创建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; 如果要在Execute()内部创建FInputBuffer,那么线程应该暴露在实际创建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; . 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; (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |