Forum > General

Is there something like crossplatform PostThreadMessage in Lazarus?

(1/2) > >>

stab:
Hi all,

As I've understood from info at the forum both SendMessage and PostMessage is crossplatform(at least Linux) in Lazarus.

If there isn't a crossplatform PostThreadMessage available, how could one send a message to a background-thread?

Is it possible to use PostMessage even when communicating to a background-thread?
(First parameter in both PostMessage and PostThreadMessage seem to be LongWord)

Regards
Staffan %)

JuhaManninen:
There is no PostThreadMessage.
What is the difference between PostMessage and PostThreadMessage anyway?
It should be possible to use PostMessage for threads but I am not sure. I never did it myself.
You can try it and tell later if it works.

Juha

stab:
Hi Juha,

Tried to signal a thread by PostMessage, but not luck.

Made a unit(threadmanager.pas) with a ThreadManagerObject, ThreadMessageObject, ThreadQueueObject and a TManagerClientThreadObject and a testprogram as in the attachment ThreadManagerTest_pas.zip.

It seems to work well, but I would be glad to know if this is crossplatform. Furthermore I guess there is a smarter way to get hold of the queue of a certain thread than through an object associated with a string in a TStringList. Any suggstions are appreciated!

As you can see from the code the testprogram has two clientthreads subclassed from TManagerClientThread. Could you please explain why member FThreadManager isn't directly visible in the subclass(had to add property ThreadMngr to make it) %)

Regards
Staffan

JuhaManninen:
Please include the project .lpr and .lpi files into your package next time. Now I created a new project, added your files there and changed the main form manually.

For portability you must define "UseCThreads" (for Linux at least) as noted here:
  http://lazarus.firmos.at/index.php?topic=8852.0

I found a small error but it didn't create any problems because FmemStream is not used anywhere:

constructor TThreadMessageObject.Create(const Command, Params: string);
begin
  Create; // Call Constructor above. (was: inherited Create;)
  FCommand := Command;
  FParams := Params;
end;

  ThreadQueue:=TThreadQueue(FThreadList.Objects[FThreadList.IndexOf(IntToStr(ThreadId))]);
Using TStringList.Objects property is OK but now you had to use IntToStr just to get the right data type. Not good indeed!
A Java-like TMap<TThreadID, ThreadQueue> would be just perfect here. In fact there are generics containers in FPC trunk 2.5.1. You can experiment with them if you like.
There may be the right container type available in the current libraries, too, but I don't know where.

Member FThreadManager isn't visible to subclass because it is private. It should be protected. Note also the warnings like:
"clientthread1.pas(15,15) Note: Virtual method "TClientThread1.Execute;" has a lower visibility (private) than parent class TThread (protected)"

When I "Stop ClientThreads" I get an exception:
"Suspending one thread from inside another one is unsupported (because it is unsafe and deadlock prone) by *nix and posix operating systems."

It seems suspending a thread is not portable.

Otherwise it is a very international program. It even has "Ikkuna" and "Fönster". Congratulations! :-)

Juha

JuhaManninen:
More feedback:
PostMessage is actually a stitched-in feature to emulate Windows. Your program does't gain anything by using it.
When you do:

--- Code: ---msg := ThreadMngr.PopMessage(ThreadId);
PostMessage(Application.MainForm.Handle,LM_USER,1,integer(ThreadMessageObject));

--- End code ---
You could as easily do:

--- Code: ---Synchronize(GetMyMessage);
Synchronize(NotifyOthers);

--- End code ---

It could even simplify your program by doing so.
It needs co-operation from the thread but so does your current implementation, and actually so does any other program.
For example when your main thread is busy it doesn't always update the UI. You must add Application.ProcessMessages, and that is basically the same kind of co-operation.

Another thing: you don't need the pointer syntax for this program.
Remove "pThreadMessageObject = ^TThreadMessageObject;" and change every reference of "pThreadMessageObject" into "TThreadMessageObject".
The code becomes cleaner. For example:

--- Code: ---procedure TfrmThreadManagerTest.ListBox1DblClick(Sender: TObject);
var
  ThreadMessageObject : TThreadMessageObject;
  lbx : TListBox;
begin
  lbx := Sender as TListBox;
  ThreadMessageObject := TThreadMessageObject.Create('UpdateParams',lbx.Items[lbx.ItemIndex]);
  if lbx = ListBox1 then
    FThreadManager.PushMessage(FClientThread1.ThreadID, ThreadMessageObject)
  else
    FThreadManager.PushMessage(FClientThread2.ThreadID, ThreadMessageObject);
end;

--- End code ---

Please realize that a variable like ThreadMessageObject here is actually a pointer, it just doesn't use the clumsy pointer syntax.
Once you realize it, you can pretty much forget it and be happy. It is possible to write big non-trivial programs without any pointer syntax.

The func had some other improvements, too. For example it is a good idea to use the type-safe cast "as" in a big project. Saves you lots of debugging.

Juha

Navigation

[0] Message Index

[#] Next page

Go to full version