2017-02-27 51 views
1

得到的數據從我所理解的閱讀尼克·霍奇斯,這段代碼應該是罰款:德爾福TTask從主線程

TTask.Run(
    procedure 
    var 
    resp, tmp: string; 
    req: boolean; 
    bwriter: TBinaryWriter; 
    myfile: TFileStream; 
    begin 
    //tell the user to wait 
    TThread.Queue(TThread.CurrentThread, 
     procedure 
     begin 
     LoginButton.Text := 'Please wait...'; 
     end 
    ); 

    //some checks 
    try 
     resp := GetURL('... here I get a result from the server...'); 
     if (resp = fOKstatus) then 
     begin 
     req := true; 

     myfile := TFileStream.Create(TPath.Combine(TPath.GetHomePath, 'docs.mkb'), fmCreate); 
     try 
      bwriter := TBinaryWriter.Create(myfile, TEncoding.Unicode, false); 
      try 
      bwriter.Write(UsernameEdit.Text); 
      bwriter.Write(AppIDEdit.Text); 
      bwriter.Close; 
      finally 
      bwriter.Free; 
      end; 
     finally 
      myfile.Free; 
     end; 
     end 
     else 
     begin 
     req := false; 
     end; 
    except 
     req := false; 
    end; 

    //final 
    TThread.Queue(TThread.CurrentThread, 
     procedure 
     begin 
     if (req = true) then 
     begin 
      LoginButton.Text := 'Success!'; 
      ShowMessage('Close the app to complete the registration.'); 
     end 
     else 
     begin 
      LoginButton.Text := 'Login failed.'; 
     end; 
     end 
    ); 

    end 
); 

這將運行在一個獨立的線程,並鏈接到與調用主線程到Queue()。實際上,在開始時我使用這種方法更新Button的Text


問題。看看這些2線:

bwriter.Write(UsernameEdit.Text); 
bwriter.Write(AppIDEdit.Text); 

我需要獲得用戶名和的AppID(這是一個隨機碼)從處於主線程UI兩個編輯控件。它是否正確?

我想我應該打電話Queue(),但到目前爲止該計劃運作良好。

我可以安全地以這種方式取值嗎?我沒有更新任何東西,我只需要獲取數據,但我不確定混合2個不同任務的內容是否危險/不好做法。

回答

4

您關心的兩行代碼不是線程安全的。您必須與主線程同步全部 UI訪問,無論是讀寫。 TThread.Queue()異步,所以它不適合從UI中檢索值的目的。使用TThread.Synchronize()相反,這是同步

TTask.Run(
    procedure 
    var 
    resp, tmp, username, appid: string; 
    req: boolean; 
    bwriter: TBinaryWriter; 
    myfile: TFileStream; 
    begin 
    //tell the user to wait 
    TThread.Queue(nil, 
     procedure 
     begin 
     LoginButton.Text := 'Please wait...'; 
     end 
    ); 

    //some checks 
    try 
     resp := GetURL('... here I get a result from the server...'); 
     if resp = fOKstatus then 
     begin 
     req := true; 

     TThread.Synchronize(nil, 
      procedure 
      begin 
      username := UsernameEdit.Text; 
      appid := AppIDEdit.Text; 
      end 
     ); 

     myfile := TFileStream.Create(TPath.Combine(TPath.GetHomePath, 'docs.mkb'), fmCreate); 
     try 
      bwriter := TBinaryWriter.Create(myfile, TEncoding.Unicode, false); 
      try 
      bwriter.Write(username); 
      bwriter.Write(appid); 
      bwriter.Close; 
      finally 
      bwriter.Free; 
      end; 
     finally 
      myfile.Free; 
     end; 
     end 
     else 
     begin 
     req := false; 
     end; 
    except 
     req := false; 
    end; 

    //final 
    TThread.Queue(nil, 
     procedure 
     begin 
     if req then 
     begin 
      LoginButton.Text := 'Success!'; 
      ShowMessage('Close the app to complete the registration.'); 
     end 
     else 
     begin 
      LoginButton.Text := 'Login failed.'; 
     end; 
     end 
    ); 
    end 
); 

另外,假設主UI線程是一個開始TTask,可以在開始TTask前閱讀2個值,讓匿名方法捕獲它們:

var 
    username, appid: string; 
begin 
    username := UsernameEdit.Text; 
    appid := AppIDEdit.Text; 

    TTask.Run(
    procedure 
    var 
     resp, tmp: string; 
     req: boolean; 
     bwriter: TBinaryWriter; 
     myfile: TFileStream; 
    begin 
     //tell the user to wait 
     TThread.Queue(nil, 
     procedure 
     begin 
      LoginButton.Text := 'Please wait...'; 
     end 
    ); 

     //some checks 
     try 
     resp := GetURL('... here I get a result from the server...'); 
     if resp = fOKstatus then 
     begin 
      req := true; 

      myfile := TFileStream.Create(TPath.Combine(TPath.GetHomePath, 'docs.mkb'), fmCreate); 
      try 
      bwriter := TBinaryWriter.Create(myfile, TEncoding.Unicode, false); 
      try 
       bwriter.Write(username); 
       bwriter.Write(appid); 
       bwriter.Close; 
      finally 
       bwriter.Free; 
      end; 
      finally 
      myfile.Free; 
      end; 
     end 
     else 
     begin 
      req := false; 
     end; 
     except 
     req := false; 
     end; 

     //final 
     TThread.Queue(nil, 
     procedure 
     begin 
      if req then 
      begin 
      LoginButton.Text := 'Success!'; 
      ShowMessage('Close the app to complete the registration.'); 
      end 
      else 
      begin 
      LoginButton.Text := 'Login failed.'; 
      end; 
     end 
    ); 
    end 
); 
end; 
+0

好的你解決了我的懷疑:)但你爲什麼不打電話給TThread.CurrentThread,而你使用的是nil? –

+0

當'TThread.Queue()'的第一個參數不是'nil'時,排隊的操作鏈接到指定的線程,並且當該線程終止時,操作被取消*如果它尚未被處理本身調用'TThread.RemoveQueuedEvents()')。由於'Queue()'是異步的,如果你不小心,可能會導致未執行的操作。通過'nil'而不是避免這個陷阱。至於'TThread.Synchronize()',相同的參數基本上是多餘的和無用的。我從來沒有很好的理由將非'nil'指針傳遞給任何一種方法。 –

+0

我想即使我在TThread的子類中使用Execute,我也應該這樣做(設置nil)?而從我的理解你的評論中使用零都是最好的選擇權?非常有幫助Remy btw,謝謝 –