在Delphi中的单独线程中运行WebService的问题

时间:2010-08-08 19:28:35

标签: delphi thread-safety webservice-client tthread

我从未在任何社区提问,因为我总是自己解决问题或者可以在网上找到问题。但是有了这个,我走到了死胡同,需要帮助! 为了清楚起见 - 我转换了一个简单的应用程序,在其他地方找到它以使其使用Tthread对象。 这个想法很简单 - 应用程序使用webservice在线检查,通过THTTPRIO组件,天气并将结果放入Memo1行。

点击Button1,我们以标准方式完成它 - 使用THTTPRIO放在Form1上(在这里称为原始app中的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单元的执行过程中,我输入了以下代码:

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在线程中工作!!!

您可以找到压缩的完整代码here

3 个答案:

答案 0 :(得分:4)

当我在Delphi 2007中运行代码时,madExcept显示异常未调用CoInitialize。
在execute方法中添加对CoInitialize的调用后,将调用webservice而不会出现问题。

可能的解决方法

procedure TWeatherThread.Execute;
begin
  CoInitialize(nil);
  try
     ...
  finally
    CoUninitialize;
  end;
end;

答案 1 :(得分:1)

远景,但我在这里缺少对Synchronize的调用:

您永远不应该直接从线程代码更新GUI。

您应该将这些调用嵌入到方法中,然后使用TThread.Synchronize method调用该方法。

Delphi有一个nice demo on this 从Delphi 4开始,它在sortthds.pas子目录中包含了一个名为...\demos\threads的演示,显示了相同的内容。

- 的Jeroen

答案 2 :(得分:0)

通过动态创建RIO(RIO对象具有奇怪的生命周期)和线程化,并将结果与​​简单的Button1进行比较,可能会使问题蒙上阴影。我做了另一个没有线程调用GetForecast的按钮。看看是否有效。如果它轰炸,那么你的问题就不是线程。