据我所知,阅读Nick Hodges,这段代码应该没问题:
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
。
问题。看看这两行:
bwriter.Write(UsernameEdit.Text);
bwriter.Write(AppIDEdit.Text);
我需要从主线程UI中的两个Edit控件中检索用户名和AppID(这是一个随机代码)。这是对的吗?
我想我应该致电Queue()
,但到目前为止该计划运作良好。
我可以安全地以这种方式获取值吗?我没有更新任何东西,我只需要抓取数据,但我不确定混合2个不同任务的内容是否可能是危险/不良做法。
答案 0 :(得分:4)
您关注的2行代码不是线程安全的。您必须与所有 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;