簡體   English   中英

TThread本身的線程安全字段是線程安全的嗎?

[英]Is a Thread Safe field of TThread itself thread safe?

在此代碼中:

TMyClass = class(TThread)
public
  FInputBuffer     : TThreadedQueue<TBytes>;
protected
  procedure Execute; override;
end;

使用FInputBuffer(在TMyClass和其他類中)是否是線程安全的?

編輯:

樣本使用:在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線程開始運行之前在線程構造函數中創建的 ,並且在線程運行完成之后在線程析構函數中釋放的 ,則是的,當TMyClass對象仍然存在時,從其他線程對其進行訪問是線程安全的,因為TThreadedQueue為其內部內容提供了自己的線程安全性。 如果MyClass變量在調用btn1Click()時有效,那么您所顯示的是對多線程隊列的完全有效使用。

但是,如果FInputBufferExecute()內部創建的 ,則它不是線程安全的,因為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;

如果要在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;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM