Is there a way to do TThread.Synchronize with Timeout? - delphi

Sometimes you need to call TThread.Synchronize, but also you can enter in a deadlock situation.
For example:
Thread1.execute
procedure
begin
....
TThread.Synchronize(..)
...
end;
Then from the main thread doing something like:
Thread1.terminate;
Thread1.waitfor;
can leave to some deadlock because TThread.Synchronize will never succeed :(
I would like to know the most easy way to handle such scenario.

There is no way to use TThread.Synchronize() with a timeout.
You can use TThread.Queue() instead, passing it a procedure associated with a TEvent that you can wait on after Queue() exits. Then the main thread can signal that TEvent when it processes the request (just be sure to not free the TEvent until after the main thread has used it, unless you call TThread.RemoveQueuedEvents() to cancel the request first).
That being said, what you describe is NOT a deadlock scenario. If TThread.WaitFor() is called in the main UI thread, it processes pending Synchronize()/Queue() requests while waiting for the thread to terminate. If TThread.WaitFor() is called in another thread, then the main UI thread is free to process Synchronize()/Queue() requests normally.

Related

Why Synchronize is being locked by ShowModal?

I created a generic thread class that controls a progress form which is injected in the constructor of the thread and set as _progressForm. At the Execute method, the thread initializes the form and shows it using the function ShowModal() as shown below:
procedure TProgressThread.Execute;
begin
...
ShowForm;
end;
procedure TProgressThread.ShowForm;
begin
if Assigned(_progressForm) then
begin
Synchronize(
procedure
begin
_progressForm.ShowModal();
end);
end;
end;
What I can't understand is why my thread is locked at Synchronize? It doesn't return until the progress form is closed. Shouldn't ShowModal only lock the main thread?
TThread.Synchronize() is synchronous. It blocks the calling thread until the synced code returns from the main thread.
ShowModal() is also synchronous. It blocks the calling thread until the Form is closed.
So, when Synchronize() calls ShowModal() in the main thread, Synchronize() will not return to the worker thread until the Form is closed.
If you don't want to block the worker thread, either use TThread.Queue() instead of TThread.Synchronize(), or use TForm.Show() instead of TForm.ShowModal().
Display of progress should not block the worker thread from doing its work. You should have the thread asynchronously post progress updates to the main thread, and let the main thread decide how to display the status while the thread continues with its work. The worker thread should have no knowledge of the UI at all.

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.

ProcessMessages and use of application

I need to know if use of ProcessMessages that allow me to use entire application is legal.
Pseudo code:
Main thread button call - search.
procedure ButtonOnClick;
begin
var1 = ExecuteSearch();
end;
function ExecuteSearch:Something;
begin
thread.StartThread;
while thread.Finished do
Application.ProcessMessages;
result := something;
end;
When I use this construction I can click other parts of my software and use it. But I don't know how this works. And if its safe.
Whilst this can be made safe, you are playing with fire. You run the risk of re-entrancy. You have to make sure that the user cannot press the button again. I trust you have disabled it whilst the search is running. You must make sure that it is disabled before you first call ProcessMessages.
My advice would always be to avoid using ProcessMessages. Better would be to start the thread and arrange for it to notify the main thread when it is done. Of course, you still need to disable the button whilst the thread is running.
However, if you really must use ProcessMessages don't do it with a busy loop like this. There's not much point using an entire processor to wait for a long running search operation to complete. Use a more intelligent blocking loop like this:
while MsgWaitForMultipleObjects(1, Thread.Handle, False,
INFINITE, QS_ALLEVENTS)=WAIT_OBJECT_0+1 do
Application.ProcessMessages;
The MsgWaitForMultipleObjects function will block until either:
A message is placed on the queue, or
The thread is signaled. The thread is signaled when it is complete.
The loop terminates when the thread is signaled, but also processes any queued messages.
Though the code is safe, what you could also do is use the OnTerminate event on the thread you're starting. This way you let Delphi control how to post back from the background thread to the main thread. Internally it uses the thread's Synchronize method, which you can use yourself to let the thread post intermediate progress information to the main thread.

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.

TThread.resume is deprecated in Delphi-2010 what should be used in place?

In my multithread application
I use TThread.suspend and TThread.resume
Since moving my application to Delphi 2010 I get the following warring message
[DCC Warning] xxx.pas(277): W1000 Symbol ‘Resume’ is deprecated
If Resume is deprecated what should be used in place?
EDIT 1:
I use the Resume command to start the thread - as it is Created with 'CreateSuspended' set to True and Suspend before I terminate the thread.
EDIT 2:
Here is a link the delphi 2010 manual
Charles if do you read the code of TThread class , do you find the answer.
TThread = class
private type
..
..
..
public
constructor Create(CreateSuspended: Boolean);
destructor Destroy; override;
procedure AfterConstruction; override;
// This function is not intended to be used for thread synchronization.
procedure Resume; deprecated;
// Use Start after creating a suspended thread.
procedure Start;
// This function is not intended to be used for thread synchronization.
procedure Suspend; deprecated;
procedure Terminate;
See this link RAD Studio 2010: Community pulse: The day after. (Part 2)
Edit:
If you need to synchronize threads, you can use a scheme based on TMutex, TEvent and critical sections.
Bye.
Use TThread.Start instead of .Resume
--EDIT--
Start can of course only be used with Delphi 2010 (and later, presumably) to start a thread that was created suspended (where you would have used Resume before).
Using Resume/Suspend (or corresponding WinAPI functions) for thread synchronisation is NOT recommended. See the discussion here (have a look at Barry Kelly's comments).
Suspend and Resume were (or used to be) potentially broken in the TThread class (if you look at the source you will see that the Suspend method directly and unconditionally sets a Boolean to indicated thread suspended state rather than more robustly deriving this state from the execution count on the thread handle. Ironically the Resume method does use this more robust indicator to update the suspended state Boolean).
This is possibly why they have been deprecated. It's also why I implemented my own class to encapsulate a Windows thread with a more robust suspend and resume mechanism as well as the ability to Restart a thread once it had completed.
I'm not sure why their deprecation is supposedly related to synchronization. Suspending and resuming threads is not necessarily related to synchronization, although I can see how it might be. It's interesting to note that the equivalent methods in the .NET framework Thread class are similarly marked as obsoleted. And the same comments w.r.t synchronization appear in the Windows API documentation for thread suspend/resume.
If using deprecated methods makes you nervous and you still wish to suspend/resume you could always use the Windows API to suspend and resume the thread by reference to it's handle.
Just in case all you wanted to do was get rid of the compiler hints
(1) To get rid of the compiler hint when Starting a Thread ...
replace
MyThread := TMyThread.Create(True);
MyThread.Resume;
with
MyThread := TMyThread.Create(True);
MyThread.Start;
(2) To get rid of the compiler hint when Stopping a Thread ...
replace
MyThread.Suspend;
MyThread.Terminate;
with
MyThread.Terminate;
Not a big deal at all. Beware of attempted obfuscation.
Thread behavior control code should lie with in a thread procedure. Use appropriate sync objects and corresponding API calls in order to suspend/resume thread execution. Doing it from outside is a dangerous practice. So there was a decision to depricate it.
Use
Suspended := False; // Resume;
or
Start;
You should create the thread as follows:
constructor TSignalThread.Create;
begin
// create event handle first!
FEventHandle := CreateEvent(
{security} nil,
{bManualReset} true,
{bInitialState} false,
{name} nil);
FWaitTime := 10;
inherited Create({CreateSuspended}false);
end;
This way a call to Start is not required.
See http://www.gerixsoft.com/blog/delphi/creating-threads for an explanation why this code works.
#mghie (a little late, I know)
take for example madexcept and alike. If your application crashes and a bug report is being shown to user, that means that the dialog waits for use input. If it so happens that the crash is a result of a thread action (not necessarily a thread crashing), if you do not suspend the threads, the screen will be filled with bug report dialogs.
example 2: logging. for any particular reason, I at least, had the need to log some threads execution state. That includes the current stack trace. Now, as you (should) know, you cannot do that while the thread is running because during the time you collect information about it, the threads keeps doing stuff so by the time you finish collection, the information collected will not be consistent. Hence, you need to suspend the thread.
And I can go on with practical examples on thread management. Granted, these are not things you do in every day programming, but at least the first example I am sure that many of you are using, even if you are not aware of the internals of it. Debuggers? again, you use them.
But indeed, in all these cases, TThread is not used, since the work is done on thread handles. So, indeed, a valid example of TThread suspend usage is hard to come by. But threads in general, that's another story.

Resources