【问题标题】:Problem with running WebService in separate thread in Delphi在 Delphi 的单独线程中运行 WebService 的问题
【发布时间】:2010-08-08 19:28:34
【问题描述】:

我从来没有在任何社区提出过问题,因为我总是自己解决问题或者可以在网上找到问题。但是有了这个,我走到了死胡同,需要帮助! 说得非常清楚——我转换了一个简单的应用程序,在别处找到使它使用 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 单元中的执行过程中,我输入了以下代码:

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;

Procedure ShowWeather 在 Form1.Memo1 中显示结果。 现在有一个问题:在主线程中,单击 Button1,一切正常。当然,当 HTTPRIO 组件进行通信时,它会冻结表单。

使用 Button2,我将代码放在单独的线程中,但它不想工作!奇怪的事情发生了。当我启动应用程序并单击 Button2 时,使用 HTTPRIO 组件时出现错误。但是当我点击 FIRST Button1 和 AFTER Button2 时它可以工作一段时间(但它可以工作一段时间,只点击 5-7 次)。 我想我做错了什么,但无法弄清楚问题出在哪里以及如何解决。看起来线程单元中的代码不是线程安全的,但它应该是。请帮助如何使 HTTPRIO 在线程中工作!!!

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

【问题讨论】:

  • 当您说某事“奇怪”并且发生“错误”时,您需要更加具体。什么错误?
  • 您确实意识到您的 WeatherTread.GetForecast 中存在内存泄漏?您创建但从未释放 THTTPRIO 实例。
  • 这不是真的,@Marjan。在没有所有者的情况下创建 THTTPRIO 时,它使用接口引用计数来管理其生命周期。将其类型转换为 WeatherForecastSoap 会创建一个临时接口引用,该引用会在函数结束时释放。
  • 所有的线程代码都在这里了吗?我没有看到对CoInitialize 的呼叫。 Delphi 在为主线程初始化“ComObj.pas”时处理调用,但对于单独的线程,您可以自己调用它。顺便说一句,你在代理后面吗?
  • @Rob Kennedy:感谢您澄清这一点。我猜我是从臀部射击......

标签: delphi thread-safety webservice-client tthread


【解决方案1】:

当我在 Delphi 2007 中运行您的代码时,madExcept 显示异常CoInitialize 尚未被调用。
在执行方法中添加对 CoInitialize 的调用后,webservice 被调用没有问题。

可能的修复

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

【讨论】:

  • 不要在构造函数中调用它。构造函数在创建者的线程上下文中运行,而不是在正在创建的线程的上下文中。在Execute 方法中调用这两个函数。
  • 非常感谢!我刚刚发现自己再次谷歌搜索,但我看到你们都是真正的专业人士,非常乐于助人!您的快速回答正是有效的方法!谢谢!!!
【解决方案2】:

一个很长的镜头,但我在这里错过了对同步的调用:

你不应该直接从你的线程代码更新你的 GUI。

您应该将这些调用嵌入到一个方法中,并为此使用TThread.Synchronize method 调用该方法。

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

--杰罗恩

【讨论】:

    【解决方案3】:

    您可能会通过创建动态 RIO(RIO 对象具有奇怪的生命周期)和线程在一起,并将该结果与简单的 Button1 进行比较,从而使问题变得模糊不清。我会制作另一个没有线程调用 GetForecast 的按钮。看看这是否有效。如果它爆炸了,那么你的问题不是线程。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-26
      • 2019-08-12
      • 1970-01-01
      • 2012-05-20
      • 2015-01-24
      • 2011-04-21
      相关资源
      最近更新 更多