我正在编写一个应用程序,需要等到目录中存在文件。我已经尝试了多种方法,唯一有效的解决方案是使用Sleep/Application.ProcessMessages。
这是我尝试过的:
使用 Sleep/Application.ProcessMessages:
Result := False;
for i := 0 to iTimeout do
begin
if FileExists(fileName) do
begin
updateStatus('Conversion Completed');
Result := True;
Break;
end;
updateStatus(Format('Checking for file: %d Seconds', [i]));
Application.ProcessMessages;
Sleep(1000);
end;
此方法有效,除了我无法在等待时关闭应用程序。此外,使用Sleep/Application.ProcessMessages也有一些有据可查的问题,我宁愿避免这些问题。
使用 TThread/TEvent:
type
TMyThread = class(TThread)
private
FEventDone: TEvent;
public
constructor Create(CreateSuspended: boolean);
destructor Destroy;
procedure Execute; override;
property EventDone: TEvent read FEventDone;
end;
TformThreading = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
waitThread: TMyThread;
{ Private declarations }
public
{ Public declarations }
end;
var
formThreading: TformThreading;
implementation
{$R *.dfm}
{ TformThreading }
procedure TformThreading.Button1Click(Sender: TObject);
var
res: TWaitResult;
begin
try
waitThread.Start;
res := waitThread.EventDone.WaitFor(INFINITE);
case res of
wrSignaled: ShowMessage('wrSignaled');
wrTimeout: ShowMessage('wrTimeout');
wrAbandoned: ShowMessage('wrAbandoned');
wrError: ShowMessage('wrError');
wrIOCompletion: ShowMessage('wrIOCompletion');
end;
except
on E: Exception do
begin
ShowMessage(E.Message);
end;
end;
end;
procedure TformThreading.FormCreate(Sender: TObject);
begin
waitThread := TMyThread.Create(true);
end;
procedure TformThreading.FormDestroy(Sender: TObject);
begin
waitThread.Free;
end;
{ TMyThread }
constructor TMyThread.Create(CreateSuspended: boolean);
begin
inherited Create(CreateSuspended);
FEventDone := TEvent.Create;
end;
destructor TMyThread.Destroy;
begin
FEventDone.Free;
end;
procedure TMyThread.Execute;
begin
for i := 0 to iTimeout do
begin
if FileExists(fileName) do
begin
FEventDone.SetEvent;
Break;
end;
Application.ProcessMessages;
Sleep(1000);
end;
end;
我似乎无法让它在等待时不冻结我的主线程,但如果我可以解决冻结问题,这似乎是正确的方法。
解决问题的最佳方法是什么?
我似乎无法让它在等待时不冻结我的主线程。
当您等待某个对象时,该线程会阻塞,直到该对象发出信号。因此,当您的主线程等待事件时,它会被阻止。您观察到的行为完全是意料之中的。
查看线程的代码,它会循环,直到满足条件,发出事件信号,然后终止。换句话说,该事件没有任何目的。您可以删除它,而是等待线程。
现在,如果你这样做了,你的代码将这样做:
- 创建一个线程并开始执行。
- 等待该线程完成,阻塞主线程。
- 线程完成后继续执行。
因此,就目前而言,您的线程一事无成。您也可以在主线程中执行其代码。你又回到了起点。
你需要一种不同的心态。GUI 程序在其 UI 中是异步的。您需要遵循该模式。不要在主线程中等待。相反,一定要使用单独的线程,但在完成后让该线程向主线程发出信号。
执行此操作的最简单方法是为线程实现OnTerminate
事件处理程序。这将在线程完成其工作时触发。事件处理程序将在主线程中执行。
更一般地说,您可以使用Synchronize
或Queue
向主线程发出事件信号,但在处理终止事件的情况下,满足您的需求。
现在到线程的主体。你的方法基于轮询,睡眠。那会起作用,但它不是很漂亮。ReadDirectoryChangesW
功能是系统提供的机制,用于接收文件系统中的更改通知。这将是一种更优雅的方法。
我的建议是首先使用您当前的轮询方法解决阻塞问题。一旦明确,重构以使用ReadDirectoryChangesW
。
我正在编写一个应用程序,需要等到文件中存在文件 一个目录。我已经尝试了多种方法,唯一的 有效的解决方案是使用睡眠/应用程序.进程消息。
我不这么认为。完成任务的正确方法应该是使用ReadDirectoryChangesW函数等待发出FILE_ACTION_ADDED操作信号。
您可以在目录监视项目中找到的示例实现。