2017-05-29 4 views
-2

Ich habe gerade angefangen mit Threads zu arbeiten, benutze das onexecute Event mit Delphi 2009, indy IdTCPServer1. Ich habe eine sehr einfache Anwendung zum Testen geschrieben und erhalte eine Zugriffsverletzung beim Beenden. Die Anwendung läuft gut und macht alles, was ich will, aber ich denke, dass ich "Threads läuft" beim Beenden lassen werde. Ich habe keine Erfahrung mit Threads, also würde jede Hilfe geschätzt werden.Delphi 2009, IDTCPServer1 Zugriffsverletzung beim Beenden

Heres mein Code

unit FT_Communicator_pas; 

interface 

uses 
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
    Dialogs, StdCtrls, ScktComp, IdContext, IdTCPServer, 
    INIFiles, ExtCtrls, ComCtrls, adscnnct, 
    DB, adsdata, adsfunc, adstable, Wwdatsrc, Grids, Wwdbigrd, Wwdbgrid, 
    IdBaseComponent, IdComponent, IdCustomTCPServer; 


type 
    TfrmMain = class(TForm) 
    IdTCPServer1: TIdTCPServer; 
    PgMain: TPageControl; 
    TsMain: TTabSheet; 
    tsConfig: TTabSheet; 
    Label1: TLabel; 
    Label2: TLabel; 
    txtServer: TEdit; 
    txtPort: TEdit; 
    Panel1: TPanel; 
    Panel3: TPanel; 
    tsLog: TTabSheet; 
    mnolog: TMemo; 
    Button1: TButton; 
    Button3: TButton; 
    procedure IdTCPServer1Connect(AContext: TIdContext); 
    procedure IdTCPServer1Execute(AContext: TIdContext); 
    procedure Button3Click(Sender: TObject); 
    procedure IdTCPServer1Disconnect(AContext: TIdContext); 
    procedure Logit(const Logstr: String); 
    procedure FormShow(Sender: TObject); 
    procedure Button1Click(Sender: TObject); 
    private 
    { Private declarations } 
    public 
    { Public declarations } 
    end; 



var 
    frmMain: TfrmMain; 

implementation 
{$R *.dfm} 

procedure TfrmMain.Button1Click(Sender: TObject); 
begin 


    IdTCPServer1.Active:=FALSE; 

    application.Terminate; 
end; 

procedure TfrmMain.Button3Click(Sender: TObject); 
begin 
    IdTCPServer1.Active:=true; 
end; 

procedure TfrmMain.FormShow(Sender: TObject); 
begin 
    PgMain.ActivePage:=tsMain; 
    EnableMenuItem(GetSystemMenu(handle, False),SC_CLOSE, MF_BYCOMMAND or MF_GRAYED); 
end; 


procedure TfrmMain.IdTCPServer1Connect(AContext: TIdContext); 
begin 
    mnoLog.lines.Add ('Connected from: ' + AContext.Connection.Socket.Binding.PeerIP); 
end; 

procedure TfrmMain.IdTCPServer1Disconnect(AContext: TIdContext); 
begin 
    mnoLog.lines.Add ('Disconnected from: ' + AContext.Connection.Socket.Binding.PeerIP); 
end; 

procedure TfrmMain.IdTCPServer1Execute(AContext: TIdContext); 
var 
    myReadln,mySendln,sqlqry:string; 
begin 


    sleep(10); 

    myReadln:=AContext.Connection.IOHandler.ReadLn(); 
    mnolog.Lines.Add(AContext.Connection.Socket.Binding.PeerIP + '>' + myReadln); 
    mySendln:= AContext.Connection.Socket.Binding.PeerIP + ' Sent me ' + myReadln; 
    AContext.Connection.IOHandler.WriteLn(mySendln); 

    try 
    except 
     on E:Exception do 
     begin 
      logit('Error occured During execute function ' + #13#10 + e.message); 
     end; 
    end; 

end; 

procedure TfrmMain.logit(const logstr:String); 
var 
    curdate,Curtime:string; 
    StrGUID:string; 
begin 
    StrGUID:=FormatDateTime('YYYYMMDDHHnnsszzz', Now())+'_ '; 
    mnolog.lines.add(StrGUID +logstr); 
end; 

end. 
+0

Ihre Try/außer Block nichts drin hat. Daher kann es nichts fangen. Was ist sein Sinn? –

+0

Können Sie eine [mcve] bereitstellen. Ich vermute, dass viel mehr passiert, Einstellungen in der .dfm-Datei, die wichtig sind. Und vermutlich das andere Ende der Kommunikation. Stellen Sie kein GUI-Programm zur Verfügung. Es ist ein Schmerz, zu versuchen, dass das hier läuft. Stellen Sie eine saubere [mcve] in Form einer Konsolen-App bereit. –

+0

Ich bin Autodidakt, also weiß ich nicht einmal, wie man eine Konsolen-App macht, aber ich werde es versuchen. Auch für die Fehlersuche habe ich den Code entfernt, der im Versuch war, außer wenn ich irgendwo gelesen habe, ein Versuch/außer im Execute-Ereignis kann verhindern, dass das Steuerelement seine eigenen Ausnahmen behandelt. Vielen Dank für die Antwort – John

Antwort

2

Ihre TIdTCPServer Event-Handler enthalten unsicheren Code in ihnen.

TIdTCPServer ist eine Multithread-Komponente, deren Ereignisse im Kontext von Worker-Threads ausgelöst werden. Sie greifen jedoch direkt auf ein VCL-UI-Steuerelement (mnoLog) zu, ohne mit dem Hauptthread der Benutzeroberfläche zu synchronisieren. Schlechte Dinge passieren, wenn Sie nicht synchronisieren, da die VCL nicht Thread-sicher ist. Sie müssen ordnungsgemäß synchronisieren, wenn Sie von einem Arbeitsthread auf die Benutzeroberfläche zugreifen.

Es ist auch wichtig, die Ausführung einer synchronen Synchronisation zu vermeiden, wenn TIdTCPServer vom Haupt-UI-Thread deaktiviert wird, da dies einen Deadlock verursacht. Verwenden Sie stattdessen eine asynchrone Synchronisation.

Versuchen Sie, etwas mehr wie folgt aus:

procedure TfrmMain.IdTCPServer1Connect(AContext: TIdContext); 
begin 
    Logit('Connected from: ' + AContext.Connection.Socket.Binding.PeerIP); 
end; 

procedure TfrmMain.IdTCPServer1Disconnect(AContext: TIdContext); 
begin 
    Logit('Disconnected from: ' + AContext.Connection.Socket.Binding.PeerIP); 
end; 

procedure TfrmMain.IdTCPServer1Execute(AContext: TIdContext); 
var 
    myReadln, mySendln, peerIP: string; 
begin 
    myReadln := AContext.Connection.IOHandler.ReadLn(); 
    peerIP := AContext.Connection.Socket.Binding.PeerIP; 
    Logit(peerIP + '>' + myReadln); 
    mySendln := peerIP + ' Sent me ' + myReadln; 
    AContext.Connection.IOHandler.WriteLn(mySendln); 
end; 

procedure TfrmMain.IdTCPServer1Exception(AContext: TIdContext; AException: Exception); 
begin 
    if not (AException is EIdConnClosedGracefully) then 
    Logit('Error occured. ' + AException.Message); 
end; 

procedure TfrmMain.Logit(const Logstr: String); 
var 
    Str: string; 
begin 
    Str := Trim(Logstr); 
    TThread.Queue(nil, 
    procedure 
    begin 
     mnolog.Lines.Add(FormatDateTime('YYYYMMDDHHnnsszzz', Now()) + ': ' + Str); 
    end 
); 
end; 
+0

Danke Remy, wo wird "EIdConnClosedGracefully" definiert? Es tut mir leid, wenn es sich um eine einfache Antwort handelt. – John

+0

Ok, ich denke, ich verstehe es. Ich habe von einem Thread auf die GUI-Objekte zugegriffen. Wie mache ich das sicher? Gibt es eine einfache Ressource/Anleitung, die Sie mir dabei helfen können, Multithreading zu verstehen und damit zu programmieren? Ich schätze die Hilfe sehr. – John

+0

Ok, es funktioniert. Vielen Dank für die Hilfe – John