Postmessage LParam truncation - multithreading

My app has a worker thread, and I use PostMessage to send a string to the main thread. For 1 message, the string is truncated when it gets to the message handler in the main thread.
The string is constructed in the worker thread from a string of raw data that is like this. It ends at the last '20'.
'01010000000030000102000008850008855343414E204544474520000000000000000000'
Decoded into the string I want to send it looks like this, which is correct:
'0100 0.50000 LSB0288.588.5SCAN EDGE '
The code that creates the 'SCAN EDGE ' portion and posts it is:
tmp and s_out are strings
x := 35;
for i := 1 to 10 do
begin
tmp := '$' + copy(s,x,2);
TryStrToInt(tmp,dec);
s_out := s_out + chr(dec);
x := x + 2;
end;
PostMessage(MainHandle,UM_CLONE, UM_756, Integer(PChar(s_out)));
The message handler in the main thread is:
i is a string
i := pChar(msg.LParam);
when it gets to the main thread i looks like this in the debugger:
'0100 0.50000 LSB0288.588.5SCAN EDG'#0
How can I correct this?

You are posting the contents of a String variable that is local to the thread procedure that is calling PostMessage(). If the String goes out of scope and gets freed before the main thread processes the posted message, the memory will be garbage.
You need to either:
1) use SendMessage() instead of PostMessage() so the String stays in scope until the message handler exits:
SendMessage(MainHandle, UM_CLONE, UM_756, LPARAM(PChar(s_out)));
2) dynamically allocate a String in memory, fill it as needed, post it, and then let the main message handler free it when it is done copying it:
var
s_out: PString;
New(s_out);
...
s_out^ := s_out^ + chr(dec);
...
if not PostMessage(MainHandle, UM_CLONE, UM_756, LPARAM(s_out)) then
Dispose(s_out);
.
var
ps: PString;
i: String;
ps := PString(msg.LParam);
i := ps^;
Dispose(ps);
PS: notice I also changed your Integer() cast to LPARAM(). This is very important if you ever upgrade to Delphi XE2 or later. PostMessage() and SendMessage() use LPARAM, not Integer. You can get away with it in Delphi 7 because LPARAM is an alias for Integer in that version, but that is not the case anymore in modern Delphi versions. LPARAM is an alias for NativeUInt now. LPARAM has always been an unsinged type in the Win32 API, Delphi just got it wrong in the early versions, but Embarcadero has really been pushing for type-correctness in the RTL/VCL since adding support for 64-bit and cross-platform development. If you don't match the right data types correctly, you can cause range checks errors and such at runtime.

Related

multi-threading thread safety

I am using Delphi TThread to run multiple TCP connections to external devices. Incoming data is dissected and stored. Everything works OK but on reviewing my code I am having doubts whether it is thread safe or if I am just being lucky so far...
In the TThread.Execute method, I am calling a helper function which exists in a different unit, not being a member of any TThread or other class. The function accesses four bytes of data in a buffer, reverses the byte order and places the result in a variable of type Single, (the external devices are Big Endian).
type
TByteBuffer = array [0 .. 255] of Byte;
function ConvBufferToSingle(Buffer: TByteBuffer; J: Byte): Single;
type
TSingleByteArray = array [0 .. 3] of Byte;
var
X: Single;
begin
TSingleByteArray(X)[3] := Buffer[J];
TSingleByteArray(X)[2] := Buffer[J + 1];
TSingleByteArray(X)[1] := Buffer[J + 2];
TSingleByteArray(X)[0] := Buffer[J + 3];
Result := X;
end;
Although this seems to work, I can't understand what happens if one (or more) threads enter this function before another thread has exited. I have read articles on Thread Safe vs. Re-Entrant code, but I am still not sure how to verify that the code is thread safe.
When the function is called, I believe that the parameters are pushed onto the stack. This would happen for each TThread entering the function, but what happens in the code addressing those variables confuses me.
For peace of mind, is it better practise to turn the function into a method of the thread class?

Why doesn't this Synchronize procedure lock the main thread

I have following code:
TThread.Synchronize(nil,
procedure
begin
with Scope.New(TManualCaptchaForm.Create(img)) do
if It.ShowModal() = mrOk then
res := It.edtResolved.Text;
end
);
Why does the form appear several times when multiple TThreads use this procedure for synchronization? I know a workaround, and there is nothing unusual (e. g. no other "hand-made" ways to sync with main thread), but why am I not experiencing a lock?
Yes, Scope.New is kinda smart-pointer, BUT only i see TThread.Synchronize and passed closure? Documentation says that any method/closure passed to TThread.Synchronize will be execute inside main thread. Obviously, ShowModal must block main thread, but it didn't do that. As for me, it's very strange that any other window start behave as main thread and pump synchronization queue.
P. s. almost MVP:
TThread.Synchronize(nil,
procedure
var Form: TForm1;
begin
Form := TForm1.Create(nil);
try
Form.ShowModal();
finally
Form.Free;
end;
end
);
Run this code in 2+ threads and see bug. Anyway, now I know that synchronization queue pumped by any window message loop, not just by main form.
Btw, my question was "Why TThread.Synchronize behave so unclear/not logically?", not about my own code.
The fundamental misunderstanding here is that because .ShowModal is a blocking call you expect that it also suspends message processing. It does not. When you create a modal window the modal window takes over message processing - it must do this or the window would not function. The main thread is still processing the message loop, it is just doing it in a different context.
If you want to think of it this way, ShowModal behaves a lot like Application.ProcessMessages. This has nothing to do with Synchronize. If you examine the code for ShowModal you find :
{ ... }
Show;
try
SendMessage(Handle, CM_ACTIVATE, 0, 0);
ModalResult := 0;
{ *** Here is your message loop *** }
repeat
Application.HandleMessage;
if Application.Terminated then ModalResult := mrCancel else
if ModalResult <> 0 then CloseModal;
until ModalResult <> 0;
{ *** ------------------------- *** }
Result := ModalResult;
SendMessage(Handle, CM_DEACTIVATE, 0, 0);
if GetActiveWindow <> Handle then ActiveWindow := 0;
finally
Hide;
end;
{ ... }
If you want to prevent reentrance here you have to devise your own explicit method to do so.

Using the Delphi XE7 Parallel Library

I have a time consuming routine which I'd like to process in parallel using Delphi XE7's new parallel library.
Here is the single threaded version:
procedure TTerritoryList.SetUpdating(const Value: boolean);
var
i, n: Integer;
begin
if (fUpdating <> Value) or not Value then
begin
fUpdating := Value;
for i := 0 to Count - 1 do
begin
Territory[i].Updating := Value; // <<<<<< Time consuming routine
if assigned(fOnCreateShapesProgress) then
fOnCreateShapesProgress(Self, 'Reconfiguring ' + Territory[i].Name, i / (Count - 1));
end;
end;
end;
There is really nothing complex going on. If the territory list variable is changed or set to false then the routine loops around all the sales territories and recreates the territory border (which is the time consuming task).
So here is my attempt to make it parallel:
procedure TTerritoryList.SetUpdating(const Value: boolean);
var
i, n: Integer;
begin
if (fUpdating <> Value) or not Value then
begin
fUpdating := Value;
n := Count;
i := 0;
TParallel.For(0, Count - 1,
procedure(Index: integer)
begin
Territory[Index].Updating := fUpdating; // <<<<<< Time consuming routine
TInterlocked.Increment(i);
TThread.Queue(TThread.CurrentThread,
procedure
begin
if assigned(fOnCreateShapesProgress) then
fOnCreateShapesProgress(nil, 'Reconfiguring ', i / n);
end);
end
);
end;
end;
I've replaced the for-loop with a parallel for-loop. The counter, 'i' is locked as it is incremented to show progress. I then wrap the OnCreateShapeProgress event in a TThread.Queue, which will be handled by the main thread. The OnCreateShapeProgress event is handled by a routine which updates the progress bar and label describing the task.
The routine works if I exclude the call to the OnCreateShapeProgress event. It crashes with an EAurgumentOutOfRange error.
So my question is simple:
Am I doing anything anything stupid?
How to do you call an event handler from within a TParallel.For loop or TTask?
The most obvious problem that I can see is that you queue to the worker thread.
Your call to TThread.Queue passes TThread.CurrentThread. That is the very thread on which you are calling TThread.Queue. I think it is safe to say that you should never pass TThread.CurrentThread to TThread.Queue.
Instead, remove that parameter. Use the one parameter overload that just accepts a thread procedure.
Otherwise I'd note that the incrementing of the progress counter i is not really handled correctly. Well, the incrementing is fine, but you then read it later and that's a race. You can report progress out of order if thread 1 increments before thread 2 but thread 2 queues progress before thread 1. Solve that by moving the counter increment code to the main thread. Simply increment it inside the queued anonymous method. Added bonus to that is you no longer need to use an atomic increment since all modifications are on the main thread.
Beyond that, this QC report seems rather similar to what you report: http://qc.embarcadero.com/wc/qcmain.aspx?d=128392
Finally, AtomicIncrement is the idiomatic way to perform lock free incrementing in the latest versions of Delphi.

Why does the program crash when using const string arguments?

My program has following code:
function FooBar(const s: string): string;
var
sa: AnsiString;
begin
// ..........................
sa := AnsiString(s);
sa := AnsiString(StringReplace(string(sa), '*', '=', [rfReplaceAll]));
sa := AnsiString(StringReplace(string(sa), ' ', '+', [rfReplaceAll]));
result := string(sa);
// ..........................
end;
I noticed that the program did crash "somewhere" and FastMM4 said that I had written to a freed object. As soon as I have commented out "const", the program did work.
I have read the Delphi documentation about const arguments, but I can't figure out why the const argument crashes the program. I would love to understand it.
UPDATE: The program does only crash in Delphi 6 and only if optimization is ON. If the optimization is OFF, the program will work normally. Might it be a Delphi bug?
There are a few peculiar gotchas when it comes to const string parameters.
Many years ago I helped a colleague resolve a similar peculiar problem (D3 iirc). The following simplified example doesn't look like your specific issue, but it may give you some ideas:
type
TMyClass
FString: string;
procedure AppendString(const S: string);
end;
procedure TMyClass.AppendString;
begin
FString := FString + S;
end;
Now if you have an instance of TMyClass and try to call AppendString(FString); to double up the string, you may get an access violation. (There are a few other factors that can affect if you do.) The reason is as follows:
The const prevents refcounting the string on the method call.
So FString may have refCount = 1 when its value is changed.
In which case Copy-on-Write doesn't apply and the string is reallocated. (Most likely at a different address.)
So when the method returns, S is referring to an invalid address, and triggers an AV.
For this case:
sa := s;
automatic reference counting (ARC) works. This is idiomatic way, compiler know how to work with these string - if sa will change, it creates new copy and so on.
For case of hard typecasting (though type is the same)
sa := AnsiString(s);
you tell compiler that you want to get only pointer to string, and you know how to work with this string reference. Compiler will not interfere and annoy you, but you are responsible for correct operations
P.S. I can not reproduce the problem with Delphi XE5 - both simple assigning and typecasting causes LStrLAsg (internal function) call with ARC. (Of course, compiler magic could be changed a bit)
We debugged a crash today that was a Delphi 5 compiler code-gen bug:
procedure TForm1.Button1Click(Sender: TObject);
var
s: string;
begin
s := 'Hello, world! '+IntToStr(7);
DoSomething(s);
//String s now has a reference count of zero, and has already been freed
ShowMessage(s);
end;
procedure TForm1.DoSomething(const Title: string);
var
s: AnsiString;
begin
s := AnsiString(Title);
if Now = 7 then
OutputDebugString('This is a string that is irrelevant');
end;
The Delphi 5 compiler mistakenly tries to decrement the reference counts of both
Title
s
and causes the const string's reference count to go to zero. This causes it to be freed. So when DoSomething returns, you are using a freed string.
An access violation waiting to happen.
Or, in the case of customers: happening.
That becouse AnsiString is a pointer. So, you could'n operate it as a usual strings (which mean a array of chars). Crash is random, so you can gain the crash as result of stackoverflow or access violations at any time, not depend on optimization.
Than you function FooBar return the result, sa variable are already free from mamory.
Try to use the PChar or PAnsiChar and allocate the memory for this variables as your needs.
Since it doesn't make sense to convert to AnsiString and back here, I would rewrite this as
function FooBar(const s:string):string;
begin
Result:=
StringReplace(
StringReplace(
s
,'*','=',[rfReplaceAll])
,' ','+',[rfReplaceAll]);
end;

Using string pointer to send a string through windows messages

I am trying to understand how are pointers to strings working. I have a code (not exactly original), which was written by somebody, and the person is not around here anymore, so I need to understand the idea of such usage.
var
STR: string;
pStr: ^string;
begin
STR := 'Hello world';
New(pStr);
pStr^ := STR;
PostMessage(Handle, WM_USER+1, wParam(pStr), 0);
end;
Now I know for sure, that a message handler gets the message and the pointer contains the string, which can be worked with, but what happens 'under the hood' of those operations ?
I tried to make a small project. I thought, that assigning string to what a str pointer is pointing to would actually increase refcount of the original string and not make any copies of a string, but refcount remained 1 and it seems it did copy the contents.
So get the question, what happened? Calling New on a pointer allocates an empty string, right?
After assignment I tried to look at refcount/length of a string the pointer pointed to like this PChar(#pStr^[1])[-8] but it returned nonsense (14), and the length byte was also wrong.
Additionally the questioin is, is it safe using pointers in such a way to pass on the string through windows messaging?
New(pStr) allocates a string on the heap and returns a pointer to it. Because string is a managed type, the string is default initialized, to the empty string. Since a string is implemented as a pointer, what you fundamentally have is a pointer to a pointer.
You code is perfectly fine, so long as you only post the message to your own process. Since the payload of the message is a pointer, it only means something in the context of the virtual address space of your process. If you wanted to send to a different process you'd need an IPC mechanism.
Clearly in the code that pulls the message off the queue you need to dispose of the string. Something like this:
var
p: ^string;
str: string;
....
p := Pointer(wParam);
str := p^;
Dispose(p);
Your code to query the reference count and the length is just wrong. Here's how to do it correctly:
{$APPTYPE CONSOLE}
var
pStr: ^string;
p: PInteger;
begin
New(pStr);
pStr^ := 'Hello world';
p := PInteger(pStr^);
dec(p);
Writeln(p^); // length
dec(p);
Writeln(p^); // ref count
Readln;
end.
Output:
11
1

Resources