2012-01-16 1 views
7

У меня возникли проблемы с использованием SOAP в XE/XE2 из потока. (Я не тестировал его со старым Delphis.) Простой код, который работает в основном потоке, сбой при уничтожении экземпляра THTTPReqResp с Invalid pointer operation.Невозможно уничтожить компонент THTTPReqResp в потоке

Это полная программа. Форма содержит только одну кнопку, которая вызывает btnTestClick событие:

unit Unit79; 

interface 

uses 
    SysUtils, Forms, Classes, Controls, StdCtrls, ComObj, 
    ActiveX, InvokeRegistry, SOAPHTTPTrans, Rio, SOAPHTTPClient; 

type 
    TForm79 = class(TForm) 
    btnTest: TButton; 
    procedure btnTestClick(Sender: TObject); 
    private 
    { Private declarations } 
    public 
    { Public declarations } 
    end; 

var 
    Form79: TForm79; 

implementation 

{$R *.dfm} 

procedure TForm79.btnTestClick(Sender: TObject); 
begin 
    TThread.CreateAnonymousThread(
    procedure 
    var 
     FHTTPReqResp: THTTPReqResp; 
     FHTTPRIO: THTTPRIO; 
    begin 
     if CoInitializeEx(NIL, COINIT_MULTITHREADED or COINIT_SPEED_OVER_MEMORY) = S_OK then try 
     FHTTPReqResp := THTTPReqResp.Create(nil); 
     with FHTTPReqResp do begin 
      Name := 'HTTPReqResp1'; 
      UseUTF8InHeader := True; 
      InvokeOptions := [soIgnoreInvalidCerts, soAutoCheckAccessPointViaUDDI]; 
      WebNodeOptions := []; 
     end; 
     FHTTPRIO := THTTPRIO.Create(nil); 
     with FHTTPRIO do begin 
      Name := 'HTTPRIO1'; 
      HTTPWebNode := FHTTPReqResp; 
     end; 
     // 
     FreeAndNil(FHTTPRIO); 
     FreeAndNil(FHTTPReqResp); //<-- crashes here 
     finally CoUninitialize; end; 
    end 
).Start; 
end; 

end. 

Исключение поднятый в TObject.FreeInstance на вызов _FreeMem.

procedure TObject.FreeInstance; 
begin 
    CleanupInstance; 
    _FreeMem(Self); 
end; 

стек вызовов, приводящий к этой проблеме

:75bab9bc KERNELBASE.RaiseException + 0x58 System.TObject.FreeInstance 
System.ErrorAt(2,$4052E1) System.Error(reInvalidPtr) 
System.TObject.FreeInstance System._ClassDestroy(???) 
Soap.SOAPHTTPTrans.THTTPReqResp.Destroy System.TObject.Free 
frmMain.TMainForm.btnTestClick$4934$ActRec.$0$Body 
System.Classes.TAnonymousThread.Execute 
System.Classes.ThreadProc($F83530) System.ThreadWrapper($F51050) 
:76a4339a kernel32.BaseThreadInitThunk + 0x12 :77b59ef2 
ntdll.RtlInitializeExceptionChain + 0x63 :77b59ec5 
ntdll.RtlInitializeExceptionChain + 0x36 

Я не имею ни малейшего представления о том, что происходит, почему _ClassDestroy называется вообще и почему код вылетает :(Может кто-нибудь пожалуйста, а) объясните, что я делаю неправильно, и b) исправьте мой код?

+0

D2010 еще не имеет CreateAnonymousThread. Попытка с не анонимным сейчас. Никаких сбоев с не анонимной нитью. –

+0

Threading здесь не проблема (я думаю). Он сбой аналогичен с OmniThreadLibrary (именно так я нашел эту проблему). – gabr

+3

Из документации THttprio «Когда он создается с помощью параметра nil (Delphi) или NULL (C++), он будет автоматически уничтожаться, когда количество ссылок падает до нуля». Вы явно освобождаете его. –

ответ

8

«Недопустимая операция указателя» означает, что вы освобождаете то, что не представляет собой действительную память. Иногда это может указывать на повреждение стека или кучи, но это скорее указывает, что вы освобождаете то, что уже было освобождено.

Это не удивительно, что называется _ClassDestroy. FHTTPReqResp не является нулевым, поэтому, когда FreeAndNil звонит Free на нем, Free звонки Destroy.

похоже, что ваш объект THTTPRIO приобретает собственность THTTPReqResp, которого вы дадите. Если это так, то решение прост: не освобождайте его самостоятельно.

+3

Вы правы. Освобождение только FHTTPRIO уничтожает как FastMM4 FullDebugMode. Глупый код архитектуры, я бы никогда не подумал об этом! – gabr

+0

Архитектура SOAP - это не что иное, как полный толчок «Yuck!». моменты. Я провел год, работая с ним. Моим наименее любимым аспектом этого является то, как это обычно зависит от WinInet, который является ошибкой и имеет тайм-аут/замораживание на некоторых системах Windows. Когда вы переключаетесь на обычный HTTPRIO-транспорт, вы теряете случайные зависания, но вы получаете общее снижение производительности около 40%. Хороший выбор. –

+0

Спасибо за этот ответ. У меня проблема с утечкой памяти, и, надеюсь, это ее решает. –