質問

I want to run my Thread then run application instruction. why run all after Sleep? I have a TQuery(it has many record and slow fetch) instead Sleep and when Open, Thread no run before Open TQuery. ShowMessage and Sleep are for test. What's solution?

  TCustomThread = class(TThread)
  public
    procedure Execute; override;
    procedure doProc;
  end;
.
.
.
procedure TCustomThread.Execute;
begin
  Synchronize(doProc);
end;

procedure TCustomThread.doProc;
begin
  ShowMessage('Thread');
end;
.
.
.
procedure TForm1.Button1Click(Sender: TObject);
var
  thrd : TCustomThread;
begin
  thrd := TCustomThread.Create(True);
  thrd.Resume;
  Sleep(3000);
  ShowMessage('Form');
end;
役に立ちましたか?

解決 2

Button1Click is stopping the execution of the main thread for 3 seconds.

During the sleep(3000) execution, no GDI message is processed, so the dialog boxes are NOT displayed immediately.

In fact, TCustomThread.doProc works as expected, but the dialog box is not displayed until the GDI messages are processed.

You have to change this method e.g. into:

procedure TForm1.Button1Click(Sender: TObject);
var
  thrd : TCustomThread;
  expectedEnd: TDateTime;
begin
  thrd := TCustomThread.Create(True);
  thrd.Resume;
  expectedEnd := Now+(1/24/60/60*3); 
  repeat
    Sleep(50); // or any long process
    Application.ProcessMessages; // to be called to process the GDI messages
  until Now>=expectedEnd;
  ShowMessage('Form');
end;

In short: never use Sleep() in the main GDI thread, for extended period of time (more than some ms), otherwise your application won't be responsive any more. And Windows will complain for it and ask you to kill the application!

So in your case, you have to call Application.ProcessMessages in your main thread when a long process is taken place (e.g. a TQuery), or run the query in a background thread (this is IMHO the preferred method), as we do e.g. for our Open Source mORMot framework on client side.

他のヒント

I understand your question to be

Why does the form message appear before the thread message?

Simply put, your use of Synchonize means that all the code executes on the main thread. This means that the first message box must wait for the second message box to complete.

So, why does the form message box show first? The Synchronize method is used from threads to invoke code on the main thread. This Synchronize method signals the main thread that there is work to be done and then blocks until the main thread can do it.

The main thread won't start this work whilst it is busy in an event handler as your program is. So the call to Sleep actually blocks both threads because both threads are waiting on the main thread.

So to re-cap, the Synchronize method blocks until the main thread completes the work described in the procedure passed to Synchronize. If the main thread is busy then Synchronize blocks until the main thread completes its busy tasks.


Looking more broadly at your question you describe long running database tasks happening on the main thread. There is the fundamental problem. You must not have those tasks on the main thread. The main thread is dedicated to serving the GUI. That requires it to be responsive at all times and be able to service its message queue. Putting long running tasks on the main thread will destroy your GUI. Put those tasks on worker threads away from the main thread.

I suspect that you are using Synchronize because you've realised that the GUI is unresponsive because of your database code. And you reason that you can use a thread to keep the GUI responsive. But that can never work. The main thread must process messages in a timely manner. If the database code does not do so then you cannot service the message queue from the outside. There has to be co-operation.

The bottom line here is that long-running tasks must execute away from the main thread.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top