2

MySQLデータベース(DataModuleおよびMyDACコンポーネントを使用して接続)を使用するBDS2006を使用してアプリケーションを開発しました。
システム(Windows XP)の起動時にアプリケーションを起動したいので、起動フォルダにアプリケーションのショートカットを含めました。

起動時に、MySQLサービスが開始される前にアプリケーションが起動します。したがって、「MySQLに接続できません」というエラーが発生します。

そこで、アプリケーションの起動時に空白を挿入し、MySQLが実行されているかどうかを確認しました。実行されていない場合は、実行されるまで待ちます。

function ServiceGetStatus(sMachine, sService: PChar): DWORD;
  {******************************************}
  {*** Parameters: ***}
  {*** sService: specifies the name of the service to open
  {*** sMachine: specifies the name of the target computer
  {*** ***}
  {*** Return Values: ***}
  {*** -1 = Error opening service ***}
  {*** 1 = SERVICE_STOPPED ***}
  {*** 2 = SERVICE_START_PENDING ***}
  {*** 3 = SERVICE_STOP_PENDING ***}
  {*** 4 = SERVICE_RUNNING ***}
  {*** 5 = SERVICE_CONTINUE_PENDING ***}
  {*** 6 = SERVICE_PAUSE_PENDING ***}
  {*** 7 = SERVICE_PAUSED ***}
  {******************************************}
var
  SCManHandle, SvcHandle: SC_Handle;
  SS: TServiceStatus;
  dwStat: DWORD;
begin
  dwStat := 0;
  // Open service manager handle.
  SCManHandle := OpenSCManager(sMachine, nil, SC_MANAGER_CONNECT);
  if (SCManHandle > 0) then
  begin
    SvcHandle := OpenService(SCManHandle, sService, SERVICE_QUERY_STATUS);
    // if Service installed
    if (SvcHandle > 0) then
    begin
      // SS structure holds the service status (TServiceStatus);
      if (QueryServiceStatus(SvcHandle, SS)) then
        dwStat := ss.dwCurrentState;
      CloseServiceHandle(SvcHandle);
    end;
    CloseServiceHandle(SCManHandle);
  end;
  Result := dwStat;
end;  

コードソース

// if MySQL not running then sleep until its running
procedure TForm1.FormCreate(Sender: TObject);
begin
  while(ServiceGetStatus(nil, 'MySQL5.5') <>4 ) do
   begin
     sleep (200);
   end;  
end;

私のアプローチが正しいかどうか知りたいですか?同じことを提案しない場合。
また、これはウィンドウを使用してプログラミングなしで行うことができますか?

4

1 に答える 1

3

メインスレッドでスリープすることは決して良い考えではありません。

スレッドで待機し、MySQL の実行中にメイン スレッドにメッセージを投稿することをお勧めします。

@mghie からのコメントへの回答:

Sleep() を呼び出すよりも、イベントを待機する方が優れている (または異なる) のはなぜでしょうか?

イベント駆動型 GUI は、優れたプログラミング手法と見なされています。待機はありません。イベントが発生すると、データベース接続のステータス変更が GUI に通知されます。Sleep() ループで待機している場合、アプリケーションは応答していないように見えます。そして、 Application.ProcessMessages を呼び出してそれを処理することは、実際には良い習慣ではありません。

MySQL がスレッドで実行されるまで待機する方法の例:

const
  WM_MySQL_READY = WM_USER + 1;  // The unique message id 

type
  TForm1 = class(TForm)
  ...
  private
    procedure OnMySqlReady( var Msg: TMessage); message WM_MySQL_READY;
  ...
  end;

あなたのスレッドで:

Constructor TMyThread.Create( OwnerForm : TForm);
begin
  Inherited Create( false); 
  FOwnerForm := OwnerForm; // Keep for later use 
  Self.FreeOnTerminate := true;
end;

procedure TMyThread.Execute;
var 
  SQL_started : boolean;
  sleepEvent : TSimpleEvent;
begin
  sleepEvent := TSimpleEvent.Create;
  try
    repeat
      SQL_started := (ServiceGetStatus(nil, 'MySQL5.5') = 4);
      sleepEvent.WaitFor(200);  // Better than sleep();
    until SQL_started or Terminated;
  finally
    sleepEvent.Free;
  end;
  // Inform main thread
  PostMessage( FOwnerForm.Handle,WM_MySQL_READY,WPARAM(SQL_started),0);  
end;

わかりました、@mghie を少し誤解しました。彼の質問はwhy the TSimpleEvent.WaitFor() is better than Sleep() inside the thread.

背景については、thread-sleep-is-a-sign-of-a-poorly-designed-program を参照してください。

要するに、Sleep()スレッドをディープ スリープ状態にし、制御が最高の周期レートで返されることはありません (まれなケースでは)。

TSimpleEvent.WaitFor()一方、タイミングとウェイクアップに関してははるかに敏感です. (Windows は真のリアルタイム OS ではなく、タイミングが保証されていないことに注意してください)。とにかく経験則として、スレッドでは、Sleep() の代わりに TSimpleEvent.Waitfor() を使用します。

MySQL サーバーへの接続の待機を停止する必要が生じた場合は、コードを調整することができます。

constructor TMyThread.Create(OwnerForm: TForm; cancelEvent : TSimpleEvent);
begin
  inherited Create(false);
  FOwnerForm := OwnerForm;  // Make sure it's assigned
  FCancelEvent := cancelEvent; // Make sure it's assigned
  Self.FreeOnTerminate := true;
end;

procedure TMyThread.Execute;
var
  SQL_started : boolean;
  cancel : boolean;
begin
  repeat
    SQL_started := (ServiceGetStatus(nil, 'MySQL5.5') = 4);
    cancel := (FCancelEvent.WaitFor(200) = wrSignaled);
  until SQL_started or Terminated or cancel;
  // Inform main thread
  PostMessage( FOwnerForm.Handle,WM_MySQL_READY,WPARAM(SQL_started),0);
end;

接続が確立される前にスレッドを中止するには、MyEvent.SetEvent を呼び出すだけです。


待機中に何が起こっているかをユーザーに知らせたい場合は、スレッドからスプラッシュ スクリーンを表示することもできます。

そのような例については、 Peter Below の Threaded Splashscreen for Delphiを参照してください。このコードは、VCL コンポーネントや、メイン スレッドとの同期に関連するものを一切使用していないことに注意してください。

次も参照してください:データベース接続 (時間がかかる場合があります) の実行中にスプラッシュ スクリーンを表示する

于 2012-06-02T07:47:20.670 に答える