Is it possible to send messages between Tasks (OmniThreadLibrary)? - delphi

My app will have several tasks for various actions.
All tasks are created in FormCreate and terminated in FormDestroy, they are always running as long as the app is running.
The main thread's only purpose is to handle user I/O and send user inputs to the appropriate task or receive task information to be displayed in the main form.
There will be data that has to be transferred between tasks.
Example:
I will have task A doing data processing.
It will send some of it's results to the main thread for displaying.
It will also have to send some (other) data to task B, which will transfer the data to another PC.
Task C will receive some data from a hardware device and has to send this data to task A for processing.
etc...
As I understand so far, sending messages with OmniThreadLibrary is always between the task and the thread that created the task (Main thread and task A, or Main thread and task B).
How can I send messages directly between any two tasks?
Or is there any problem with my approach so far and it should be done completely different?

Possible. You have to create a communication channel in the owner and pass it to both tasks. In the task you then call Task.RegisterComm to register this communication channel. From that point onwards, all messages received on this channel will be dispatched using the standard OmniThreadLibrary mechanisms (i.e. exactly as if they would be sent from the owner).
See demo 08_RegisterComm for an example.
procedure TfrmTestRegisterComm.FormCreate(Sender: TObject);
begin
FCommChannel := CreateTwoWayChannel(1024);
FClient1 := CreateTask(TCommTester.Create(FCommChannel.Endpoint1))
.Run;
FClient2 := CreateTask(TCommTester.Create(FCommChannel.Endpoint2))
.Run;
end;
function TCommTester.Initialize: boolean;
begin
Task.RegisterComm(ctComm);
Result := true;
end;

Related

How to be notified for time changes in Windows Service

I created a WindowProc to be notified for system time changes:
constructor TJJWScheduler.Create;
begin
fTimeChangeWnd := Classes.AllocateHWnd(TimeChangeWndProc);
end;
procedure TJJWScheduler.TimeChangeWndProc(var msg: TMessage);
var
i: integer;
begin
case msg.Msg of
WM_TIMECHANGE:
begin
// my things
end;
end;
end;
This code is running inside a Windows Service.
The problem is that it isn't fired when I change the system time!
Why not the broadcast message (WM_TIMECHANGE) isn't delivered to my window?
There is another way to do this without a loop?
EDIT
I don't known why, but I hardcoded the PeekMessage to process messages to that window, and everything comes to work fine. The code below solved my problem:
var
msg: TMsg;
if PeekMessage(msg, fTimeChangeWnd, WM_TIMECHANGE, WM_TIMECHANGE, PM_REMOVE) then
begin
TranslateMessage(msg);
DispatchMessage(msg);
end;
This workaround is very strange, because I already have others windows processing messages (by generic ProcessMessages), only this one isn't processing its messages.
The reason your window was not receiving the WM_TIMECHANGE messages is that your window is created from a secondary thread.
Each thread in a process has its own message queue. Synchronous messages are delivered when you service the message queue, so ever for a non-queued message like WM_TIMECHANGE you do need to service the secondary threads message queue in order for messages to be delivered.
For example, look at the documentation for GetMessage, the most common way to pull messages of the queue:
The function dispatches incoming sent messages until a posted message is available for retrieval.
The same is true for PeekMessage. It dispatches incoming sent messages before peeking the queue.
There are a handful of other ways for sent messages to be dispatched, but these are the primary ones.
Now, I suspect that it may be inconvenient for you to periodically dispatch messages from your secondary thread. If your secondary thread does nothing else then it can simply sit in the traditional GetMessage, TranslateMessage, DispatchMessage loop. And most of the time it will happily block in GetMessage dispatching any incoming sent messages. But if your secondary thread does more work then that's probably not a viable option.
You are already running and servicing a message queue on the main service thread. It may make more sense to make your listener window have affinity with the main service thread. Do that by creating it from code that runs in the main service thread.
Note also that AllocateHWnd is documented not to be thread-safe. You must not call it from any thread other than the main thread of the process. So, if you do wish to remain on a secondary thread, you'll need to use CreateWindow rather than AllocateHWnd. But this is perhaps yet another good reason to move this window onto the main thread.

Should I use a mutex for TCP client send or code my own queuing mechanism?

Delphi XE2, Indy V10, Windows 7 Pro - but I think I have a general conceptual problem.
Indy's TCP client is synchronous - it uses blocking calls.
However parts of my application are asynchronous - I want to send data over TCP and wait for a response when A) the 3rd party serial port component reports input from the serial port (it appears to be asynchronous & run in it's own thread, posting messages to my application's main form's Windows message queue) and B) when one of several timers expires (also asynchronous)
My application's handling of these async events needs to make a blocking call to send data over TCP and get a response before the next TCP data can be sent. E.G.
procedure OnSerialPortRxChar(...);
begin
if SendTCpData(...) = 'OK' then ...
end;
procedure OnTimerExpiry(...);
begin
if SendTCpData(...) = 'OK' then ...
end;
These should not interrupt each other, but currently do.
Obviously, my function SendTCpData needs some sort of blocking mechanism to prevent reentrant calls, or a queuing mechanism. Given that the caller needs to know the result, is my best solution a mutex? The problem is that the TCP transaction is just one line in the 20 line SendTCpData function which those asynch events can invoke.
I hope that I have explained this comprehendably. If not, please request more information.
Thank you very much in advance for your help.
If your serial library is AsyncPro, I would go with a single-threaded solution. There is more than one way to skin a cat, and I am not saying that you could not use a multi-threaded solution. But given that the AsycPro events will be running in the main thread, and you are not currently using threading in your application, this may be the simplest way forward.
In this solution we use a re-entry gate and a queue. The following is a mix of Delphi and pseudo-code.
var
isInTCP: boolean = False;
function DoSendTCP: boolean;
begin
isInTCP := True;
try
result := SendTCpData(...) = 'OK'
finally
isInTCP := False
end
end;
procedure OnSerialPortRxChar(...);
// This is safely re-entrant.
begin
repeat
if isInTCP then
Push the event onto a queue
else if DoSendTCP then
// Calling DoSendTCP may cause re-entry.
etc...
;
if (queue is empty) or isInTCP then break;
Pop from head of queue
until False
end;
You can use TIdAntiFreeze. Just drop it on your main form. Your call will still be blocked but your GUI will not be blocked. You may want to use some timeouts with your client though.

how to get the information that did when thread is paused

how can i get actions ,i did when my thread is paused after resumed (Sorry for my bad english )
ok i will explain with code
function mythreadf(p:Pointer):DWORD stdcall;
var i:Integer;
begin
for i:=0 to 1000000 do begin
if myevent.WaitFor(INFINITE)=wrsignaled
then
begin
if Form1.RadioButton1.Checked then ShowMessage('Checked');
Form1.Label1.Caption:=IntToStr(i);
end;
end;
end;
i am pausing and resuming my thread using resetevent and setevent
after i paused my thread by clicking resetevent button and then i checked radiobotton1 after that when resume my thread by using setevent again .dont send error occuring and applications closing :(
can any one help me in this issue
regards
Edit 1:
Error image
http://i49.tinypic.com/11r7nkn.jpg
Accessing VCL UI controls directly in a worker thread is NOT thread-safe (even ShowMessage() is not thread-safe. Use the Win32 API MessageBox() directly instead). All kinds of bad things can happen, including crashes. You must delegate your UI access to the main thread instead. The TThread class has a Synchronize() method for that purpose. Or you can use any other inter-thread synchronization of your choosing, such as by using SendMessage() to send custom messages to a hidden window created in the main thread via AllocateHWnd() or CreateWindow/Ex().
Your thread, as Remy says, should not be accessing the checkbox. Also it's bad programming style. Your background thread has a purpose? That purpose will help you find a name. If you create a class that inherits from TThread, you will get farther, faster.
interface
type
TMyElephantCountingThread = class(TThread)
protected
FResultStr:String; // holds something for later display on the user interface
FOptionChecked:Boolean; // set from main thread, to tell background thread whether or not a checkbox option is checked.
....
end;
....
implementation
....
function TMyElephantCountingThread.ElephantCounterResults;
begin
// all data fields in here is local to this thread
if FOptionChecked then
FResultStr := IntToStr(FIntegerValue);
end;
As you can see my code above uses only fields that belong to my thread object.
If FOptionChecked needs to be set equal to the value of Checkbox.checked, that must be done in the main thread.
You can not copy and paste write code from your foreground thread (which can access your VCL objects) into your background thread code (which can not safely access those objects), and not expect problems.

How to add OnComplete event to bitmap.SaveToFile('img.bmp');

i want to halt my application when my bitmap is completely saved?
Unless you are calling that method in a separate thread I'm fairly certain that it will be completely saved at the point at which the method returns:
bitmap.SaveToFile(..);
// file is completely saved at this point
What is it that leads you to believe that it isn't completely saved at this point?
The only wrinkle might be that with "lazy writes" Windows itself might not yet have completed the business of physically writing the file to the disc, but as far as your application (or any other application) is concerned, that is irrelevant. If you attempt to access the file before Windows has completed committing it to disc that application will simply "block" until it can safely access the file, but you don't need to specifically handle this, it "just works".
If you want to halt your application cleanly there are several options:
1) Close the main form. When you close the main form, the application will close.
procedure TForm1.SaveAndClose(Filename:String);
begin
Bitmap.SaveToFile(filename);
Application.Mainform.Close;
end;
2) Call Application.Terminate. This shuts down your application abruptly, but does run any finalization code. It is normally invoked when the application receives a WM_Quit message or the main form closes.
procedure TForm1.SaveAndClose(Filename:String);
begin
Bitmap.SaveToFile(filename);
Application.Terminate;
end;
3) Post wm_Close to your application/main form. This has the added advantage that any other messages in queue for the application are processed. It is equivalent to pressing CTRL-F4 or pressing the "X" in the upper right on your main form. The only issue is that if the message queue is full then it may not ever reach the form (rare).
procedure TForm1.SaveAndClose(Filename:String);
begin
Bitmap.SaveToFile(filename);
postMessage(Application.MainForm,wm_close,0,0):
end;
4) Call Halt( ExitCode:Integer ). This is a bit more extreme and will terminate the application. Finalization code will still be run, but memory is not guaranteed to be freed. Optionally you can set an exit code that will be returned back to the calling application.
procedure TForm1.SaveAndClose(Filename:String);
begin
Bitmap.SaveToFile(filename);
Halt(0);
end;

delphi - terminate all the threads (TThread) on closing application

My application is a tcp/ip server, with main thread created only once & listening all the time. When new client connects, the main thread creates the new thread of TClientThread type. There is however no list of running Client threads, as that would make my app a bit complicated... is there any way to execute "terminate" method on all the threads, even if the thread is busy (in my case "busy" means it's waiting for the data, where the timeout set is about 30 sec ... so I have to kill it anyway, without waiting.)?
The simple closing application seems not to run "terminate" method on the threads, which ends up with memory leaks reported by FastMM...
Memory leaks on shutdown are nothing to worry about - going to the trouble of freeing memory before returning control to the operating system is a waste of time and needlessly slows down application exit. All you really need to do is ensure that all data has been saved, and all interprocess handles (such as semaphores and mutexes) correctly released, and exit away.
For notifying clients, the best you can do would be a strategy somewhat like this:
Add all client-handling threads to some list somewhere (with suitable locking on creation, destruction and iteration)
Make client threads remove themselves from the list upon termination, and have the last item removed from the list set an event (manual reset event, e.g. TEvent in SyncObjs) if the server is shutting down
Introduce polling (e.g. select or equivalent with a timeout) or other kind of interruption (e.g. SO_RCVTIMEO / SO_SNDTIMEO) in what would otherwise be long-running blocking routines, monitoring the Terminated property
On shutdown, lock the list and iterate through it, calling Terminate, and then wait for the event to be signaled; of course, the listening socket which adds items to the list should be closed and known to be closed before iterating through the list
Sounds like this article may help
What you'll see if you click that link:
Using Semaphores in Delphi, Part 2:
The Connection Pool
By: Cary Jensen
Abstract: Semaphores are used to
coordinate multiple threads and
processes. That semaphores provide
multiple threads with simultaneous
access to a shared resource is
highlighted by the
TFixedConnectionPool class described
in this article.
I use a KillThreadList: TList global.
I monitor it in my thread as:
while (Not Terminated) do
begin
inc(Inker);
if (WaitForSingleObject(FTick, finterval) = WAIT_TIMEOUT) then
Begin
if Inker >= 10 then
Begin
ProcessTables;
Inker := 0;
sleep(1000);
End;
if KillThreadList.Contains(ThreadID) = True then Terminate;
End;
end;
I also test for the KillThreadList in my processes to let me opt out of them before completion, where safe to do so.
I pass the OnTerminate event out to the Main thread and remove the ThreadID from the KillList there. I use this model extensively and it has not failed me yet.
procedure TfrmProcessQualcommLocations.OnTerminateThread;
var
ThreadID : Cardinal;
i : integer;
aStatusBar :TStatFrame;
begin
ThreadID := (Sender as Tthread).ThreadID;
for i := 0 to StatusBarList.Count -1 do
Begin
if StatusBarList.Items[i].ThreadID = ThreadID then
Begin
aStatusBar := StatusBarList.Items[i];
KillThreadList.Extract(ThreadID);
StatusBarList.Extract(aStatusBar);
aStatusBar.Free;
break;
End;
End;
self.Refresh;
end;
In the case above, I am also removing some GUI stuff.
Hope that helps.
SpringerRider

Resources