[Lazarus] Lazarus implementation of TListView etc?

Bo Berglund bo.berglund at gmail.com
Sat Oct 31 18:47:24 CET 2015


On Sat, 31 Oct 2015 13:28:40 +0000, Mark Morgan Lloyd
<markMLl.lazarus at telemetry.co.uk> wrote:

>What I'd do is change the main code to be a loop to output 
>your test messages without starting a background thread, and to loop for 
>say a minute with Sleep() and CheckSynchronize(): if this crashes then 
>you've got bigger problems.
>
>Once this runs enable your comms thread and get it to output a couple of 
>messages via Synchronize(), again this should not crash while the main 
>program is running.
>

>I hope somebody else will comment about how much housekeeping FPC does 
>here, but I do believe you've got a race condition: what happens if the 
>main thread (i.e. the overall process) terminates faster than the 
>background thread?
>
>> When I run it in Lazarus there is a pop-up window saying:
>> 
>> Project IndyTCPtest raised exception class 'External: SIGSEGV'.
>> 
>>  At address 3132
>
>Make sure you're compiling with debugging enabled.
>

>Start off with a very simple program to /only/ test a background thread. 
>I'd suggest leaving Indy etc. out of it until you're confident that it 
>works and never throws an exception, /particularly/ during startup and 
>shutdown.

Mark,
thank you very much for your excellent descriptions and tips!

I did not know of CheckSynchronize before but I immediately threw in a
number of such calls in the existing code that throws the SIGSEGV
exception and Lo-and-behold! I am now getting the event output I was
expecting and no SIGSEGV exception! :)

New console output:

Creating TCP client
Start communications at time 26
Connecting to www.sunet.se on port 80
Going to sleep 500 at time 26
Event: Socket connected! Time = 101 ms  <== only previous event
Waking up from sleep 500, at time 526
Going to sleep 300 at time 526
Waking up from sleep 300 at time 826
Terminating thread
Event: Socket disconnected! Time = 903 ms <== new event
Event: Thread terminated! Time = 927 ms <== new event
Freeing FComm at time 927


Now I will return to the test code and do a better main loop as well
as trying to send something to the server.

The sending part is a bit of a mystery to me as well because the
socket is owned by the reading thread and I don't currently know the
best way to actually tell it to transmit some data.
I got stuck by the non-appearance of the event execution before...

As you have seen I have used a website as the target just in order to
verify the connect and disconnect events. To do real work I will need
to get a test server going on my laptop which responds to actual
commands sent by the client.

Here is the current code for the reading thread. The FClient object is
created within the thread in the constructor and freed in the
destructor.
I need to add a Write method that accepts input data in a byte array
or similar and safeguard that against manipulation from other
threads...

type
  TRxDataEvent = procedure(Sender: TObject; const AData: TIdBytes) of
object;
  TRxErrorEvent = procedure(Sender: TObject; AException: Exception) of
object;

  { TSockReadThread }
  TSockReadThread = class (TThread)
  private
    FClient: TIdTCPClient;
    FData: TIdBytes;
    FException: Exception;
    FOnConnected: TNotifyEvent;
    FOnDisconnected: TNotifyEvent;
    FOnData: TRxDataEvent;
    FOnError: TRxErrorEvent;
    procedure DoConnected;
    procedure DoDisconnected;
    procedure DoData;
    procedure DoError;
    function GetConnected: boolean;
  protected
    procedure Execute; override;
  public
    constructor Create(AHost: String; APort: TIdPort); reintroduce;
    destructor Destroy; override;
    property Connected: boolean read GetConnected;
    property OnConnected: TNotifyEvent read FOnConnected write
FOnConnected;
    property OnDisconnected: TNotifyEvent read FOnDisconnected write
FOnDisconnected;
    property OnData: TRxDataEvent read FOnData write FOnData;
    property OnError: TRxErrorEvent read FOnError write FOnError;
  end;

Tested towards the webserver before posting above message:
-----------------------------------------------------------------
- Added public method Write(AData: TIdBytes); to TSockReadThread 

- Implemented it as follows:
procedure TSockReadThread.Write(AData: TIdBytes);
begin
  if FClient.Connected then
     FClient.IOHandler.Write(AData);
end;
 
- Added extra lines in the main DoRun code:
    Writeln('Sending HELO to server');
    if FComm.Connected then
    begin
       FSendString := 'HELO'#13#10;
       SetLength(FSendData, Length(FSendString));
       Move(FSendString[1],FSendData[0],Length(FSendString));
       FComm.Write(FSendData);
    end;

Result in the console in Lazarus:

Creating TCP client
Start communications at time 25
Connecting to www.sunet.se on port 80
Going to sleep 500 at time 26
Event: Socket connected! Time = 99 ms
Waking up from sleep 500, at time 526
Sending HELO to server
Going to sleep 300 at time 526
Event: <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>302 Found</title>
</head><body>
<h1>Found</h1>
<p>The document has moved <a href="https:///">here</a>.</p>
<hr>
<address>Apache/2.4.7 (Ubuntu) Server at localhost Port 80</address>
</body></html>

Event: Socket disconnected! Time = 711 ms
Event: Connection Closed Gracefully. Time= 711ms
Event: Socket connected! Time = 716 ms
Waking up from sleep 300 at time 826
Terminating thread
Event: Socket disconnected! Time = 917 ms
Event: Thread terminated! Time = 926 ms
Freeing FComm at time 926
End of program at time 1127

So I *am* actually receiving data too! HOORAY!
But something is not timed correctly, for instance connection is
reported at T=716 after the client has been disconnected...
So there is still some work to be done.

Finally
My communications object does not use Synchronize() for the events.
Should I add this back now that CheckSynchronize seems to have cured a
few "shortcomings"?


-- 
Bo Berglund
Developer in Sweden





More information about the Lazarus mailing list