加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

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;

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读