Fragmenty programu:
Najpierw tworzę klasę, pochodną (dziedziczną?) po klasie TThread, która zawiera elementy do komunikacji:
Code: Select all
TKomunikacja = class(TThread)
ModBusRTUDriver1: TModBusRTUDriver;
PLCBlock1: TPLCBlock;
SerialPortDriver1: TSerialPortDriver;
procedure PLCBlock1Update(Sender: TObject);
procedure SerialPortDriver1CommErrorReading(Error: TIOResult);
private
public
Constructor Create(CreateSuspended : boolean);
destructor Destroy(); override;
protected
procedure Execute; override;
end;
Code: Select all
WatekKomunikacja: TKomunikacja;
Code: Select all
procedure TForm1.Timer1Timer(Sender: TObject);
begin
WatekKomunikacja.Terminate;
WatekKomunikacja := NiL;
end;
Procedury
Code: Select all
procedure PLCBlock1Update(Sender: TObject);
procedure SerialPortDriver1CommErrorReading(Error: TIOResult);
Code: Select all
Form1.Timer1.Enabled := False;
Code: Select all
procedure TForm2.Timer1Timer(Sender: TObject);
begin
If not Assigned(WatekKomunikacja) Then WatekKomunikacja := TKomunikacja.Create(False);
end;
I teraz opis problemu:
Ponieważ biblioteka PascalSCADA nie ma zaimplementowanej obsługi timeoutu przy "zniknięciu" wirtualnego portu COM, więc aplikacja "wisi". Stąd pomysł na komunikację w nowym wątku, ponieważ wątek ten mogę zniszczyć jak będzie "wisiał".
A problem jest taki, że z czasem zwiększa się ilość pamięci używana przez aplikację.
Uruchomiłem moduł heapTRC, z którego wynika, że wyciek pamięci jest gdzieś przy okazji wątków.
Podejrzewam, że nie usuwam nieaktywnego wątku z pamięci.
Ktoś wie, jak to zrobić poprawnie?
Wstawiam jeszcze pozostałe procedury z klasy:
Code: Select all
constructor TKomunikacja.Create(CreateSuspended: boolean);
begin
FreeOnTerminate := False;
inherited Create(CreateSuspended);
SerialPortDriver1 := TSerialPortDriver.Create(NiL);
SerialPortDriver1.Active := False;
SerialPortDriver1.OnCommErrorReading := @SerialPortDriver1CommErrorReading;
SerialPortDriver1.COMPort := '';
ModBusRTUDriver1 := TModBusRTUDriver.Create(NiL);
ModBusRTUDriver1.CommunicationPort := SerialPortDriver1;
PLCBlock1 := TPLCBlock.Create(NiL);
PLCBlock1.AutoRead := True;
PLCBlock1.AutoWrite := False;
PLCBlock1.MemAddress := 4000;
PLCBlock1.MemReadFunction := 3;
PLCBlock1.MemWriteFunction := 16;
PLCBlock1.PLCStation := 1;
PLCBlock1.ProtocolDriver := ModBusRTUDriver1;
PLCBlock1.OnUpdate := @PLCBlock1Update;
end;
destructor TKomunikacja.Destroy();
begin
inherited Destroy;
inherited Free;
end;
procedure TKomunikacja.Execute;
const
i : Integer = 0;
var
portyCOM : TMemo;
port : String;
znaleziony : Boolean = False;
listaPortow : String;
begin
portyCOM := TMemo.Create(NiL);
While Not Terminated Do
begin
repeat
Form1.Timer1.Enabled := False;
listaPortow:=GetSerialPortNames;
ExtractStrings([','], [], PChar(listaPortow), portyCOM.Lines );
For port in portyCOM.Lines Do
begin
If port = 'COM48' Then znaleziony := True;
end;
sleep(1);
until znaleziony;
PLCBlock1.AutoRead := True;
If Not SerialPortDriver1.Active Then
begin
SerialPortDriver1.COMPort := 'COM48';
SerialPortDriver1.Active:=True;
end;
PLCBlock1.Read;
i := i + 1;
If i = 10 Then
begin
i := 0;
z := z + 1;
end;
Sleep(1);
end;
Destroy();
end;