Проблема с запуском WebService в отдельном потоке в Delphi - PullRequest
3 голосов
/ 08 августа 2010

Я никогда не задавал вопросов ни в одном сообществе, так как всегда решал проблемы сам или мог найти их в Интернете. Но с этим я зашел в тупик и мне нужна помощь! Чтобы было очень ясно - я преобразовал простое приложение, найденное в другом месте, чтобы оно использовало объект Tthread. Идея проста - приложение проверяет онлайн с помощью веб-сервиса, через компонент THTTPRIO, прогноз погоды и помещает результаты в строки Memo1.

Нажав на кнопку 1, мы сделаем это стандартным способом - используя THTTPRIO, помещенный в форму Form1 (здесь он называется 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;

В процедуре Execute в модуле 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. Но это работает некоторое время, когда я нажимаю ПЕРВАЯ кнопка 1 и ПОСЛЕ ТОГО, что кнопка 2 (но работает некоторое время, только 5-7 нажатий). Я полагаю, что я делаю что-то не так, но не могу понять, где проблема и как ее решить. Похоже, что код в многопоточном модуле не является потокобезопасным, но так и должно быть. Помогите пожалуйста как заставить HTTPRIO работать в потоке !!!

Вы можете найти полный код здесь .

Ответы [ 3 ]

4 голосов
/ 09 августа 2010

Когда я запускаю ваш код в Delphi 2007, madExcept показывает исключение CoInitialize не был вызван.
После добавления вызова CoInitialize в метод execute веб-служба вызывается без проблем.

Возможное исправление

procedure TWeatherThread.Execute;
begin
  CoInitialize(nil);
  try
     ...
  finally
    CoUninitialize;
  end;
end;
1 голос
/ 09 августа 2010

В общем, но мне не хватает вызовов для синхронизации здесь:

Вы никогда не должны обновлять свой графический интерфейс непосредственно из кода потока.

Вы должны встраивать эти вызовы в метод,и вызовите этот метод, используя для этого TThread.Synchronize метод .

В Delphi about есть хорошая демонстрация этого .
.демо под названием sortthds.pas в подкаталоге ...\demos\threads, которое показывает то же самое.

- jeroen

0 голосов
/ 09 августа 2010

Возможно, вы омрачаете проблему, выполняя динамическое создание RIO (объекты RIO имеют странное время жизни) и объединяя их в потоки и сравнивая этот результат с простой кнопкой1. Я бы сделал еще одну кнопку, которая вызывает GetForecast без потоков. Посмотри, работает ли это. Если это бомбы, то ваша проблема не в потоке.

...