Delphi TTask从主线程获取数据 [英] Delphi TTask get data from main thread
问题描述
根据我对尼克·霍奇斯的理解,这段代码应该没问题:
From what I have understood reading Nick Hodges, this code should be fine:
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
.
This runs in a separated thread, and it is linked to the main thread with the calls to Queue()
. In fact, at the beginning I am updating the Text
of a Button using this method.
问题.看这两行:
bwriter.Write(UsernameEdit.Text);
bwriter.Write(AppIDEdit.Text);
我需要从主线程UI中的两个Edit控件中检索用户名和AppID(这是一个随机代码).这是正确的吗?
I need to retrieve the username and AppID (which is a random code) from two Edit controls that are in the main thread UI. Is this correct?
我想我应该调用Queue()
,但是到目前为止该程序运行良好.
I guess that I should call Queue()
, but so far the program is working well.
我可以通过这种方式安全地获取值吗?我什么都没有更新,我只需要获取数据,但是我不确定混合来自2个不同任务的内容是否危险/不好.
Can I take the values in this way safely? I am not updating anything, and I just need to grab the data, but I am not sure if mixing contents from 2 different tasks can be dangerous/bad practice.
推荐答案
您关注的两行代码不是线程安全的.您必须与主线程同步,以进行 all UI访问,包括读取和写入. TThread.Queue()
是异步,因此不适用于从UI检索值的目的.请使用TThread.Synchronize()
同步:
The 2 lines of code you are concerned about are NOT thread-safe. You must synchronize with the main thread for all UI access, both reading and writing. TThread.Queue()
is asynchronous, so it is not suitable for the purpose of retrieving values from the UI. Use TThread.Synchronize()
instead, which is synchronous:
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个值,并让匿名过程捕获它们:
Alternatively, assuming the main UI thread is the one starting the TTask
, you can read the 2 values before starting the TTask
and let the anonymous procedure capture them:
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;
这篇关于Delphi TTask从主线程获取数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!