Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
This is my Requirement:
Need application or Task which runs on 24/7 with configurable Time interval(in Delphi).
What i did so far:
So i have decided to go for Windows service.
Then I have created the windows service in Delphi.
The process is
1. Created Windows service Start():
procedure TDemo.ServiceStart(Sender: TService; var Started: Boolean);
begin
MyServiceThread := TMyThread.Create(False); //Call the thread
MyServiceThread.Resume;
end;
2. Windows service stop();
procedure TDemo.ServiceStop(Sender: TService; var Stopped: Boolean);
begin
MyServiceThread.Terminate;
end;
Thread's Execute method:
procedure TMyThread.Execute;
begin
MyTask();
end;
MyTask() have some functionality and it may take 30 secs to 5 min time to complete the task.
If Now i start the Service,then it call execute method and call MyTask() inside it. Then i t completes task. It will happen only once. Because no Looping at all.
Then i have created the Task scheduler and set Time interval of 10
mins and call the batch file which Starts my Windows service and
Stops.
Now Everything is working fine. Every 10 min my tasks was completed.
What are all the other possibility to do this instead of Task Scheduler? Is it possible to do inside Service itself? which one is best method?
Thinking and found one solutions:
1.Creating the Timer inside the Thread. But Timer needs to set time as Configurable one.It may be one day or one week and so on..
What is the maximum time support by Timer?
Is it possible to do with timer?
Is any other way to do this?
Please give me some suggestion to go for better solution.
You can use the approach of creating the timer.
Now if you can schedule task based on system clock (for instance start at 3 PM) then you can use next approach. Instead of changing the timer interval so that it will fire at that specific time you keep your timer at 1 minute interval. And then everytime the timer fires you simply check if the system time is greater than the scheduled time. If it is you do what processing it is needed else you do nothing.
So now you only need one organized list storing all the scheduled tasks in sorted order so that youz don't need to iterate through whole list and check for every task individual if it needs to be executed.
Now if using the systems closk is not an option due the fact that user is able to change it implement your own counter which will be increased everytime the timer fires. So now you only need to adapt your timing logic to your counter system.
EDIT: The approach I'm suggesting is comonly used in time ridden multiplayer browser games where each task takes certain amount of time. So server just stores when certain event would ocur based on when command for some task was isued and how much time takes for that task to compleete.
First of all, I dont't know your Delphi version, but generally TThread.Resume is deprecated. You should use TThread.Start. But even so, you don't need to start the thread, because it is created with False parameter - ie not suspended state.
The Execute() executes only once, because you did it so.
The code below is a simple thread that "executes" within a time interval.
TMyThread = class(TThread)
private
fRefreshInterval: Integer; // milliseconds
fTerminateEvent: TEvent;
procedure SetRI(const Value: Integer);
protected
procedure Execute; override;
public
constructor Create(const aRefreshInterval: Integer = 600000);
destructor Destroy; override;
property RefreshInterval: Integer write SetRI;
end;
//// implementation
constructor TMyThread.Create;
begin
inherited Create(False);
fRefreshInterval := aRefreshInterval;
fTerminateEvent := TEvent.Create(nil, True, False, '');
Priority := tpLowest;
FreeOnTerminate := True;
end;
destructor TMyThread.Destroy;
begin
try
if not Terminated then
begin
Terminate;
fTerminateEvent.SetEvent;
end;
fTerminateEvent.Free;
except
//
end;
inherited;
end;
procedure TMyThread.Execute;
begin
while not Terminated do
begin
try
// your code here
except
// something bad happened
end;
fTerminateEvent.WaitFor(fRefreshInterval);
end;
end;
procedure TMyThread.SetRI(const Value: Integer);
begin
InterlockedExchange(fRefreshInterval, Value);
end;
If you want to execute your task every XX minutes, you have to keep in mind the time required for your task execution and should do something like:
procedure TMyThread.Execute;
var
taskStartedAt: Cardinal;
taskDuration: Cardinal;
begin
while not Terminated do
begin
taskStartedAt := GetTickCount;
try
// your code here
except
// something bad happened
end;
taskDuration := GetTickCount - taskStartedAt;
if (fRefreshInterval > taskDuration) then
fTerminateEvent.WaitFor(fRefreshInterval - taskDuration);
end;
end;
Anyway, TTimer and the Task Scheduler are options too.
Having a timer inside your Windows Service is one option. You can also check if your previous instance has completed before kicking off a new one. However, if you have to control the services time to time, this may not be the right option.
Over years, I have found Autosys to be the most useful scheduling agent. It comes with client-server model. So you can control the jobs from your Autosys client tool.
TechScheduler is another option, but now it is very old fashioned.
I would rather go with the "Scheduled Task" approach. It's the windows native approach on
such a task and would you only require to create a console application which is called
every interval you define in the scheduled task.
Related
i want to check if Anonymous thread is running,i have an idea which is to monitor the thread status every 1s, if it Exists, restart the work again..
I've got the thread ID, now how to check the status ?
procedure TForm2.Button5Click(Sender: TObject);
begin
TThread.CreateAnonymousThread(procedure ()
var i : integer;
begin
inc(i);
label1.caption := TThread.Current.ThreadID.ToString;
end).Start;
end;
Threads do not just stop. If your thread stops functioning it is because your code has a defect. Even the simple code in the question contains two defects. It reads a local variable before it is initialized and it uses a VCL method away from the main thread.
The entire premise of your question is wrong. You don't need to monitor whether or not your thread is still running. You simply need to fix the defects in your code so that it does not fail.
A better understanding of what threads are and how to use them, will help you. A thread is usually a way to get something done without holding up the user-interface. If you want the user to wait for something to finish, don't use a thread, just put the work code in the buttonclick event handler without any thread creating.
You said
every 1s, if it Exists, restart the work again
That makes no sense. If the thread exists, it's still busy working so there's no need to restart it. Maybe you should tell us what work you want the thread to do exactly.
In the example below (taken from Background Operations on Delphi Android, with Threads and Timers, you can see that the Synchronize procedure is called when the work is done, so that's how you know that that thread is done with it's work.
procedure TForm2.Button5Click(Sender: TObject);
begin
TThread.CreateAnonymousThread(procedure ()
var i : integer;
begin
inc(i); // some work here
TThread.Synchronize (TThread.CurrentThread,
procedure ()
begin
label1.Caption := TThread.Current.ThreadID.ToString;
end);
end).Start;
end;
TThread.CreateAnonymousThread is a function which returns an instance of new Thread like this:
var ms:TThread;
ms:=TThread.CreateAnonymousThread( .....
You have an instance - ms "aka Thread" and you can work with this object...
I have developed an application that connects to SQL Server database and reads some data from tables every 1 second.
For this purpose I use TTimer but the delay of the database response affects my application performance.
I know a little about TThread in Delphi, what I want to know now is the difference between using TTimer and TThread? And using TThread instead of TTimer is useful for my application performance in this case?
The main difference between the two can be found in their class definition:
TTimer = class(TComponent)
TThread = class
While the TTimer class extends TComponent and is a component itself, TThread is an abstract class which extends TObject.
TThread exposes static methods like TThread.Sleep and a peculiar protected method called Execute which must be implemented in the derived class in order to perform the desired job.
TThread directly uses the Processes and Threads functions of the guest OS.
... for this purpose I use TTimer but the delay of Database response affect on my application performance
The reason why this happens is because the OnTimer event of the TTimer object is executed in the calling thread: when a TTimer component is put into a form and its OnTimer event is implemented, the code is executed in the main thread.
The TThread approach is more flexible: if for some reason the code must be performed in the main thread, this can be achieved nesting a sinchronized block inside the thread's Execute method.
If you want to execute database requests in a repeated manner after some time interval, you better consider using a TThread in combination with a TEvent object.
An example of class definition using TEvent:
TMyThread = class(TThread)
private
FInterval: Integer;
FWaitEvent: TEvent;
protected
procedure Execute; override;
procedure TerminatedSet; override;
public
constructor Create(Interval: Cardinal; CreateSuspended: Boolean);
destructor Destroy; override;
end;
The implemented class:
constructor TMyThread.Create(Interval: Cardinal; CreateSuspended: Boolean);
begin
inherited Create(CreateSuspended);
FInterval := Interval;
FWaitEvent := TEvent.Create(nil, False, False, '');
end;
destructor TMyThread.Destroy;
begin
FWaitEvent.Free;
inherited;
end;
procedure TMyThread.TerminatedSet;
begin
inherited;
FWaitEvent.SetEvent;
end;
procedure TMyThread.Execute;
begin
inherited;
while not Terminated do begin
//do your stuff
//wait fo some amount of time before continue the execution
if wrSignaled = FWaitEvent.WaitFor(FInterval) then
Break;
end;
end;
The WaitFor method called on the FWaitEvent object allows to wait for the desired amount of time.
The implementation of the thread's TerminatedSet method allows to put the FWaitEvent object in a signaled state and then exit from the thread before the interval has elapsed.
TTimer is a message-based timer. It posts WM_TIMER messages to the message queue of the thread that creates it. Your database operations are blocking that thread from processing new messages in a timely manner. Assuming your TTimer is in the main UI thread, that is why your app performance suffers. Moving the database operations into a worker thread prevents the main thread's message loop from being blocked.
This doesn't specifically address your q, but as noted in a comment to one of
the other answers, polling a database at the frequency you're doing isn't a good idea, especially if other users are trying to access it.
There are various ways to get notifications from database servers when data changes, without needing to continually poll them. This Embarcadero paper has a very useful review of what's available for various DBMSs:
http://docwiki.embarcadero.com/RADStudio/XE8/en/Database_Alerts_%28FireDAC%29
If your Delphi version includes FireDAC, as you'll see from the link that you could use TFDEventAlerter to receive notifications of data changes on the server if your DBMS supports
it.
If you're using Interbase or Firebird (and maybe some others), there are alternate Delphi components available that don't require FireDAC, e.g. TIBEventAlerter in the IBExpress ibrary for Interbase.
I would suggest keeping your TTimer if you want to on your main form
Then inside your TTimer create a TTask
http://docwiki.embarcadero.com/RADStudio/XE8/en/Tutorial:_Using_Tasks_from_the_Parallel_Programming_Library
https://delphiaball.co.uk/2014/09/08/using-ttask-from-the-parallel-programming-library/
And doing all your DB work in there, but as others have suggested checking every 1 second is not very good practice.
Something like this :
Global var downloaddata : ITask
TimerTimer.Timer(Sender: TObject);
begin
if downloaddata.Status = TTaskStatus.Running then
begin
//If it is already running don't start it again
Exit;
end;
downloaddata := TTask.Create (procedure ()
var //Create Thread var here
MyConnection : TFDConnection;
MyQuery : TFDQuery;
begin
//Do all your Query logic in here
//If you need to do any UI related modifications
TThread.Synchronize(TThread.CurrentThread,procedure()
begin
//Remeber to wrap them inside a Syncronize
end);
//If you have Query variables and this is running on mobile with ARC
//remember to set their connection : properties to nil to avoid memory leaks
//http:stackoverflow.com/questions/32010583/what-happens-to-database-connection-objectsmydac-tmyconnection-under-arc
MyQuery.connection := nil
end);
downloaddata.start
There are much better solutions available this is just a quick basic answer but it should guide you into something better.
Doing logic in your thread would keep your UI repsonsive, but beware that TThread.Syncronize will wait for the main form and depending on the situation TThread.queue would be a better call.
Whether TTimer or TThread is used, it is recommended to run a query only to get data that has been changed. To do that you need to:
Add a 'modified' (TIMESTAMP) column to each table
Add a 'deleted' (TIMESTAMP) column to each table
Add a trigger for INSERT OR UPDATE to update 'modified' field with CURRENT_TIMESTAMP
Add a DESC index on the 'modified' field to speed up queries
Never delete a row, only update 'deleted' field with CURRENT_TIMESTAMP
After first read, it is enough to ask for new data:
select c.* from 'customers' as c where c.modified > '2019...'
You read all data at once and store the result in a temporary memory-array.
After closed the dataset >> you compare (syncronized) with the main-array.
To update data >> run a separate SQL.
I would like to do two things at the same time in delphi, for example, to run at the same time as the two-timer,,,,How to use a method that?
For example, let's look at this simple example, here are two timers and these timers running consecutively but I would like to run the timers at the same time,,,but how?
procedure TForm1.Button1Click(Sender: TObject);
begin
if Button1.Caption = 'START' then
begin
Timer1.Enabled := True;
Timer2.Enabled := True;
Button1.Caption := 'FINISH'
end
else if Button1.Caption = 'FINISH' then
begin
Timer1.Enabled := False;
Timer2.Enabled := False;
Button1.Caption := 'START';
end;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
var
i : integer;
begin
for i := 0 to 50 do
begin
Memo1.Lines.Add(IntToStr(i));
sleep(500);
end;
end;
procedure TForm1.Timer2Timer(Sender: TObject);
var
k : integer;
begin
for k := 0 to 50 do
begin
Memo2.Lines.Add(IntToStr(k));
sleep(500);
end;
end;
end.
" I would like to run the timers at the same time,,,but how?"
This is not possible.
Everything in the main thread is running in one sequence.
There is no way to run two procedures at the same time, even using timers.
The idle part of the main thread checks the message queue for messages.
They are handled one by one. This is what is happening when your timer events are called.
During the execution of your timer event, the main thread does nothing but execute this event.
So be careful with the complexity of your timer event code and keep it short and simple.
If you want better multitasking performance (or your timer event is too complex), you must use threads.
Threads are executed "parallel" to your main thread with their own stack.
How parallel is interpreted depends on the OS and also how many cores the CPU has.
Access to the VCL part from your threads is not possible without proper protection, like Synchronize.
This means that the thread waits until the synchronized part has been executed in the main thread.
It is also possible to queue messages asynchronously from the thread to be executed main thread.
You can find an example of multithreading in the Delphi samples, ThrdDemo.
Do not call Sleep inside the TTimer.OnTimer handler. Instead, set yout timer interval to 500 and it will fire every 500 miliseconds. Both timers will fire and you will have a sensation that two things are running at the same time.
It´s an ilusion, however, since both codes are running inside the same thread (the main thread), but depending on your requirements, the behavior may be acceptable.
I have some data base optimization routines that need to execute periodically. I am currently using a TTimer but the main VCL freezes and is very hacky ... I would like to know what the best method is to have a low cpu consumption and execute these routines. I think putting the routines in separate threads with low thread priority is the best way.
Any ideas ?
If possible, it is much better to just code all your threads to do the most important thing that needs to get done at that particular time. Messing with thread priorities can cause serious performance problems if you don't know exactly what you're doing. Instead, just code your threads like this:
Is there anything important to do? If so do it.
Is there anything not too important to do? If so, do a little of it.
Go to step 1.
Say you do use thread priorities. Imagine this:
A low priority task, A, grabs a lock on the database.
A normal priority task, B, requires lots of CPU time, it steals the CPU from the low priority task.
A normal priority task, C, requires access to the database. But it can't run because the low priority task holds the lock on the database and task B gets the CPU over task A.
Now, task C has to wait until task B is complete to get access to the database. But it should be timeslicing with task B.
One way of doing it is creating your "db optimization thread" something like:
type
// a record defining database connection
TConnectionSettings = record
DatabaseName: string;
Server: string;
Port: Word;
UserName: string;
Password: string;
end;
type
TDBOptimizationThread = class(TThread)
private
FConnection: TDatabaseConnection; // your database connection... I don't know what libraries you are using
FQuery: TQuery; // your specific db query
protected
procedure Execute; override;
public
constructor Create(AConnectionSettings: TConnectionSettings;
destructor Destroy; override;
end;
implementation
constructor TDBOptimizationThread.Create(AConnectionSettings: TConnectionSettings;
begin
inherited Create(True); // create suspended
//FreeOnTerminate := True; // if you want it to be freed when you terminate it
// create FConnection and FQuery objects
// setup FConnection parameters based on AConnectionSettings
end;
destructor TDBOptimizationThread.Destroy;
begin
// destroy objects
inherited Destroy;
end;
procedure TDBOptimizationThread.Execute;
begin
while NOT Terminated do
try
// check if it's time to run query
// you can use a private variable of TDateTime type that will hold
// last timestamp of when the query ran, etc.
if ItsTimeToRunQuery then begin
// check if we still have db connectivity
if NOT FConnection.Connected then
// ouch, try to connect...
FConnection.Connect;
FQuery.SQL.Text := 'Your optimization query';
FQuery.Execute; // or ExecSQL or whatever the method is based on your db library
end;
except
on E: Exception do begin
// log exception, something went wrong!!
end;
end;
end;
It is very important that your db connection is created and destroyed in this thread, otherwise you will have issues...
So, let's start a db optimization thread
...
var
LConnSettings: TConnectionSettings;
// you may want a private TDBOptimizationThread variable rather than
// a variable in a method, but I leave that to you
LDBOptimizationThread: TDBOptimizationThread;
begin
LConnSettings.Database := 'MyDatabase';
LConnSettings.Port := 1234;
LConnSettings.Server := 'localhost';
// continue with connection settings...
LDBOptimizationThread := TDBOptimizationThread.Create(LConnSettings);
LDBOptimizationThread.Start; // start it
end;
You can of course make it a low priority, but if your queries are not going to run for more than a few seconds at each time, I don't see a reason for that, but feel free to contradict.
IMHO, a low priority thread is the way to go for this kind of task. But you do not have to create different threads for each optimization routine, handle all of them with only one thread. So it will be easier for you to execute them in some specific order or with different frequencies and you will be sure that they do not get into way of each other (from the point of DB).
I would like to have a thread running in background which will check connection to some server with given time interval. For example for every 5 seconds.
I don't know if there is a good "desing pattern" for this? If I remember corretly, I've read somewehere that sleeping thread in its execute method is not good. But I might be wrong.
Also, I could use normal TThread class or OTL threading library.
Any ideas?
Thanks.
In OmniThreadLibrary, you would do:
uses
OtlTask,
OtlTaskControl;
type
TTimedTask = class(TOmniWorker)
public
procedure Timer1;
end;
var
FTask: IOmniTaskControl;
procedure StartTaskClick;
begin
FTask := CreateTask(TTimedTask.Create())
.SetTimer(1, 5*1000, #TTimedTask.Timer1)
.Run;
end;
procedure StopTaskClick;
begin
FTask.Terminate;
FTask := nil;
end;
procedure TTimedTask.Timer1;
begin
// this is triggered every 5 seconds
end;
As for sleeping in Execute - it depends on how you do it. If you use Sleep, then this might not be very wise (for example because it would prevent the thread to stop during the sleep). Sleeping with WaitForSingleObject is fine.
An example of TThread and WaitForSingleObject:
type
TTimedThread = class(TThread)
public
procedure Execute; override;
end;
var
FStopThread: THandle;
FThread: TTimedThread;
procedure StartTaskClick(Sender: TObject);
begin
FStopThread := CreateEvent(nil, false, false, nil);
FThread := TTimedThread.Create;
end;
procedure StopTaskClick(Sender: TObject);
begin
SetEvent(FStopThread);
FThread.Terminate;
FThread.Free;
CloseHandle(FStopThread);
end;
{ TTimedThread }
procedure TTimedThread.Execute;
begin
while WaitForSingleObject(Form71.FStopThread, 5*1000) = WAIT_TIMEOUT do begin
// this is triggered every 5 seconds
end;
end;
OTL timer implementation is similar to the TThread code above. OTL timers are kept in priority list (basically the timers are sorted on the "next occurence" time) and internal MsgWaitForMultipleObjects dispatcher in TOmniWorker specifies the appropriate timeout value for the highest-priority timer.
You could use an event and implement the Execute method of the TThread descendant by a loop with WaitForSingleObject waiting for the event, specifying the timeout. That way you can wake the thread up immediately when needed, e.g. when terminating.
If the thread runs for the life of the app, can be simply terminated by the OS on app close and does not need accurate timing, why bother with solutions that require more typing than sleep(5000)?
To add another means of achieving a 5-sec event it is possible to use the Multimedia Timer which is similar to TTimer but has no dependence on your application. After configuring it (you can setup one-shot or repetitive) it calls you back in another thread. By its nature it is very accurate (to within better than 1ms). See some sample Delphi code here.
The code to call the timer is simple and it is supported on all Windows platforms.
Use CreateWaitableTimer and SetWaitableTimer