I have just compiled the Delphi VCL sample provided with PCAN-Developer 4 and tried it.
When I select "Read using an Event" on the "Messages" tab, the program locks up after a while.
That's because the VCL thread is waiting in the System.MonitorEnter call in RefreshMessages for access to the FReceivedMessages list which is blocked by the receiving thread. The receiving thread at the same time tries to write a status message which calls (via ProcessStatus -> ShowError -> TextOutput) TThread.Synchronize, which tries to switch to the VCL thread in order to access the VCL. Unfortunately that thread is already blocked while waiting in System.MonitorEnter. -> classical deadlock
My setup is special because it causes a lot "BUSWARNING" messages to be sent, so the deadlock might happen a lot more often than in other settings.
Delphi VCL sample locks up when using "Read using an Event"
Re: Delphi VCL sample locks up when using "Read using an Event"
A workaround is to pass a timeout to the MonitorEnter call in RefreshMessages, like this:
A better solution is to change ReadMessages so it takes a copy of the status message(*1), calls MonitorExit and only then passes the copy of the message to ProcesssStatus. But I haven't understood the code well enough yet to provide a possible implementation for this.
(*1: I just realized that the same problem exists for BusLoad messages: ProcessBusLoad also calls TextOutput which will end up calling TThreadSynchronize and cause the deadlock.)
Code: Select all
procedure TMainForm.RefreshMessages;
var
msg: TCanMessage;
Item: TListItem;
begin
if System.MonitorEnter(FReceivedMessages, 100) then begin
try
for msg in FReceivedMessages do begin
Item := FindMessageInListView(msg);
if Assigned(Item) then
RefreshExistingMessage(Item, msg)
else
AddNewMessage(msg);
end;
finally
System.MonitorExit(FReceivedMessages);
end;
end;
end;
(*1: I just realized that the same problem exists for BusLoad messages: ProcessBusLoad also calls TextOutput which will end up calling TThreadSynchronize and cause the deadlock.)
Re: Delphi VCL sample locks up when using "Read using an Event"
Thank you for bringing this to our attention.
A simple solution to avoid a deadlock is to use TThread.Queue instead of TThread.Synchronize in the TMainForm.TextOutput function.
A simple solution to avoid a deadlock is to use TThread.Queue instead of TThread.Synchronize in the TMainForm.TextOutput function.