Recent

Author Topic: Is there something like crossplatform PostThreadMessage in Lazarus?  (Read 10411 times)

stab

  • Full Member
  • ***
  • Posts: 234
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

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4200
  • I like bugs.
Re: Is there something like crossplatform PostThreadMessage in Lazarus?
« Reply #1 on: June 23, 2010, 10:35:18 pm »
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
Mostly Lazarus trunk and FPC 3.2 on Manjaro Linux 64-bit.

stab

  • Full Member
  • ***
  • Posts: 234
Re: Is there something like crossplatform PostThreadMessage in Lazarus?
« Reply #2 on: June 28, 2010, 10:34:52 am »
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

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4200
  • I like bugs.
Re: Is there something like crossplatform PostThreadMessage in Lazarus?
« Reply #3 on: June 29, 2010, 03:14:30 am »
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
Mostly Lazarus trunk and FPC 3.2 on Manjaro Linux 64-bit.

JuhaManninen

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4200
  • I like bugs.
Re: Is there something like crossplatform PostThreadMessage in Lazarus?
« Reply #4 on: June 29, 2010, 04:46:02 am »
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: [Select]
msg := ThreadMngr.PopMessage(ThreadId);
PostMessage(Application.MainForm.Handle,LM_USER,1,integer(ThreadMessageObject));
You could as easily do:
Code: [Select]
Synchronize(GetMyMessage);
Synchronize(NotifyOthers);

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: [Select]
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;

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
Mostly Lazarus trunk and FPC 3.2 on Manjaro Linux 64-bit.

stab

  • Full Member
  • ***
  • Posts: 234
Re: Is there something like crossplatform PostThreadMessage in Lazarus?
« Reply #5 on: July 01, 2010, 02:49:36 pm »
Thanks Juha, for your suggestions and comments.

I realized my mistake with
private
    FThreadManager: TThreadManager;  instead of
protected
    FThreadManager: TThreadManager;

Still I think there is a point using ProcessMessages as I can thus logically threat corresponding actions in the main-thread instead of writing that code in a background-thread(even if the effect will be the same).

Have been writing Delphi-program since many years and know that variables are pointer-references but due to some other error I just didn't get it to work at first. Changed the code according to your suggestions and it worked att right.

I also changed TManagerClientThread to include a protected member
FName like:
TManagerClientThread = class(TThread)
  private
  protected
    FName : string;
    FThreadManager: TThreadManager;
  public
    constructor Create(CreateSuspended : boolean);
    constructor Create(ThreadManager : TThreadManager; Name : string; CreateSuspended : boolean); reintroduce;
    destructor Destroy; override;
  end;

with parameter Name added to the constructor

and

  TThreadManager = class(TObject)
  private
    FThreadList : TStringList;

    procedure Clear;
  public
    constructor Create;
    destructor Destroy; override;

    procedure RegisterThread(ThreadName : string);
    function PushMessage(ThreadName : string; ThreadMessageObject : TThreadMessageObject) : boolean;
    function PopMessage(ThreadName : string) : TThreadMessageObject;
  end;

In this way I don't need IntToStr(ThreadId) to find a threads queue

e.g:
function TThreadManager.PopMessage(ThreadName : string): TThreadMessageObject;
var
 ThreadQueue : TThreadQueue;
begin
  ThreadQueue :=
    TThreadQueue(FThreadList.Objects[FThreadList.IndexOf(ThreadName)]);
  if ThreadQueue <> nil then
    Result := ThreadQueue.PopMessage
  else
    Result := nil;
end;
 

Still a question, could the lookup be done in a faster way with your StringHashMap?

Staffan

JuhaManninen

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4200
  • I like bugs.
Re: Is there something like crossplatform PostThreadMessage in Lazarus?
« Reply #6 on: July 01, 2010, 10:40:13 pm »
Still I think there is a point using ProcessMessages as I can thus logically threat corresponding actions in the main-thread instead of writing that code in a background-thread(even if the effect will be the same).

TThread.Synchronize does that, too. See :
http://wiki.lazarus.freepascal.org/Multithreaded_Application_Tutorial#The_TThread_Class.
Both ways work.

Quote
Still a question, could the lookup be done in a faster way with your StringHashMap?

Yes, little faster. It makes a noticeable difference only when you have many items there. Typically you don't have so many threads running at the same time.

Juha
Mostly Lazarus trunk and FPC 3.2 on Manjaro Linux 64-bit.

 

TinyPortal © 2005-2018