3

私はいつも自分で問題を解決したか、オンラインで見つけることができたので、コミュニティで質問したことはありません. しかし、これで私は行き止まりになり、助けが必要です! わかりやすくするために、他の場所で見つけた単純なアプリを Tthread オブジェクトを使用するように変換しました。アイデアは単純です。アプリは Web サービスを使用してオンラインでチェックし、THTTPRIO コンポーネントを介して天気を調べ、結果を Memo1 行に入れます。

Button1 をクリックすると、標準的な方法で実行されます。Form1 に配置された THTTPRIO を使用し (元のアプリと同様に、ここでは htt と呼ばれます)、メインおよび唯一のスレッドを使用します。

procedure TForm1.Button1Click(Sender: TObject);
var
wf:WeatherForecasts;
res:ArrayOfWeatherData;
i:integer;
begin
    wf:=(htt as WeatherForecastSoap).GetWeatherByPlaceName(edit1.Text);
    if wf.PlaceName<> '' then
    res:=wf.Details;
    memo1.Lines.Add('The min and max temps in Fahrenheit is:');
    memo1.Lines.Add(' ');
    for i:= 0 to high(res) do
    begin
        memo1.Lines.Add(res[i].Day+'   -   '+ ' Max Temp. Fahr: '+res[i].MaxTemperatureF+'   -   '+'Min Temp Fahr: '+res[i].MinTemperatureF);
    end
end;

Button2 をクリック – クラス TThread を使用します

procedure TForm1.Button2Click(Sender: TObject);
var WFThread:WeatherThread;
begin
  WFThread := WeatherThread.Create (True);
  WFThread.FreeOnTerminate := True;
  WFThread.Place := Edit1.Text;
  WFThread.Resume;
end;

WeatherThread1 ユニットの Execute プロシージャに、次のコードを追加しました。

procedure WeatherThread.Execute;
begin
  { Place thread code here }
  GetForecast;
  Synchronize (ShowWeather);
end;

...そして GetForecast コード:

procedure WeatherThread.GetForecast;
var
    HTTPRIO: THTTPRIO;
    wf:WeatherForecasts;
    res:ArrayOfWeatherData;
    i:integer;
begin
    HTTPRIO := THTTPRIO.Create(nil);
    HTTPRIO.URL := 'http://www.webservicex.net/WeatherForecast.asmx';
    HTTPRIO.WSDLLocation := 'http://www.webservicex.net/WeatherForecast.asmx?WSDL';
    HTTPRIO.Service := 'WeatherForecast';
    HTTPRIO.Port := 'WeatherForecastSoap';

    wf:=(HTTPRIO as WeatherForecastSoap).GetWeatherByPlaceName(Place);

    if Lines=nil then Lines:=TStringList.Create;

    if wf.PlaceName<> '' then
    res:=wf.Details;
    Lines.Clear;
        for i:= 0 to high(res) do
    begin
        Lines.Add(res[i].Day+'   -   '+ ' Max Temp. Fahr: '+res[i].MaxTemperatureF+'   -   '+'Min Temp Fahr: '+res[i].MinTemperatureF);
    end;
end;

プロシージャ ShowWeather は Form1.Memo1 に結果を表示します。ここで問題があります。メイン スレッドで Button1 をクリックすると、すべて正常に動作します。しかしもちろん、HTTPRIO コンポーネントが通信すると、フォームがフリーズします。

Button2 を使用して、コードを別のスレッドに入れましたが、動作したくありません! 何か奇妙なことが起こります。アプリケーションを起動して Button2 をクリックすると、HTTPRIO コンポーネントの使用時にエラーが発生します。しかし、最初の Button1 と AFTER THAT Button2 をクリックすると、しばらくは機能します (ただし、しばらくは機能しますが、5 ~ 7 回のクリックのみです)。何か間違ったことをしていると思いますが、問題の場所と解決方法がわかりません。スレッド化されたユニットのコードはスレッドセーフではないように見えますが、スレッドセーフである必要があります。スレッドで HTTPRIO を動作させる方法を教えてください!!!

圧縮された完全なコードはこちらにあります

4

3 に答える 3

4

Delphi 2007 でコードを実行すると、madExcept はCoInitialize が呼び出されていないという例外を示します。
execute メソッドに CoInitialize の呼び出しを追加すると、Web サービスは問題なく呼び出されます。

可能な修正

procedure TWeatherThread.Execute;
begin
  CoInitialize(nil);
  try
     ...
  finally
    CoUninitialize;
  end;
end;
于 2010-08-09T09:31:26.707 に答える
1

ロングショットですが、ここで同期するための呼び出しがありません:

スレッドコードからGUIを直接更新しないでください。

これらの呼び出しをメソッド内に埋め込み、TThread.Synchronizeメソッドを使用してそのメソッドを呼び出す必要があります。

Delphiについては、これに関する素晴らしいデモがあります。
Delphi 4以降、同じことを示すサブディレクトリで呼び出さsortthds.pasれるデモが含まれています。...\demos\threads

--jeroen

于 2010-08-09T10:22:49.457 に答える
0

動的な RIO の作成 (RIO オブジェクトの有効期間は奇妙なものです) を実行してスレッド化し、その結果を簡単な Button1 と比較することで、問題を曇らせている可能性があります。スレッドなしで GetForecast を呼び出す別のボタンを作成します。それが機能するかどうかを確認してください。爆撃する場合、問題はスレッドではありません。

于 2010-08-08T20:26:37.120 に答える