C# How to pause a timer? - c#

I have a C# program in which, I need the timer to stop if the user stops interacting with the program. What It needs to do is pause, and then restart when the user becomes active again. I have done some research, and found that there is commands such as:
timer.Stop();
and
timer.Start();
But I was wondering if there was like a:
timer.Pause();
And then when the user becomes active again, it picks up where it left off, and doesn't restart. If anyone can help, it would be much appreciated!
Thanks,
Micah

You achieve this by using the Stopwatch class in .NET. By simply stopping and starting you continue the use of the instance of the stopwatch.
Make sure to make use of using System.Diagnostics;
var timer = new Stopwatch();
timer.Start();
timer.Stop();
Console.WriteLine(timer.Elapsed);
timer.Start(); //Continues the timer from the previously stopped time
timer.Stop();
Console.WriteLine(timer.Elapsed);
To reset the stopwatch, just call the Reset or Restart methods, like below:
timer.Reset();
timer.Restart();

I have created this class for this situation:
public class PausableTimer : Timer
{
public double RemainingAfterPause { get; private set; }
private readonly Stopwatch _stopwatch;
private readonly double _initialInterval;
private bool _resumed;
public PausableTimer(double interval) : base(interval)
{
_initialInterval = interval;
Elapsed += OnElapsed;
_stopwatch = new Stopwatch();
}
public new void Start()
{
ResetStopwatch();
base.Start();
}
private void OnElapsed(object sender, ElapsedEventArgs elapsedEventArgs)
{
if (_resumed)
{
_resumed = false;
Stop();
Interval = _initialInterval;
Start();
}
ResetStopwatch();
}
private void ResetStopwatch()
{
_stopwatch.Reset();
_stopwatch.Start();
}
public void Pause()
{
Stop();
_stopwatch.Stop();
RemainingAfterPause = Interval - _stopwatch.Elapsed.TotalMilliseconds;
}
public void Resume()
{
_resumed = true;
Interval = RemainingAfterPause;
RemainingAfterPause = 0;
Start();
}
}

There is not a pause because it is easy to do the equivalent. You can just stop the timer instead of pausing it, then when you need to restart it you just need to specify the amount of time remaining. It might be complicated or it might be simple; it depends on what you are using the timer to do. The fact that what you do depends on what you are using the timer for is probably the reason a pause does not exist.
You might be using the timer to do something repetitively at a regular time period or you might be using the timer to count down to a specific time. If you are doing something (such as every second) repetitively then your requirements might be to restart at the beginning of that time period (a second) or at a portion of that period. What happens if the pause is for more than the time period? Usually the missed events would be ignored but that depends on requirements.
So I am trying to say that you need to determine your requirements. Then if you need help then clarify what you need.

Related

Run code at a certain time [duplicate]

I have a service written in C# (.NET 1.1) and want it to perform some cleanup actions at midnight every night. I have to keep all code contained within the service, so what's the easiest way to accomplish this? Use of Thread.Sleep() and checking for the time rolling over?
I wouldn't use Thread.Sleep(). Either use a scheduled task (as others have mentioned), or set up a timer inside your service, which fires periodically (every 10 minutes for example) and check if the date changed since the last run:
private Timer _timer;
private DateTime _lastRun = DateTime.Now.AddDays(-1);
protected override void OnStart(string[] args)
{
_timer = new Timer(10 * 60 * 1000); // every 10 minutes
_timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
_timer.Start();
//...
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
// ignore the time, just compare the date
if (_lastRun.Date < DateTime.Now.Date)
{
// stop the timer while we are running the cleanup task
_timer.Stop();
//
// do cleanup stuff
//
_lastRun = DateTime.Now;
_timer.Start();
}
}
Check out Quartz.NET. You can use it within a Windows service. It allows you to run a job based on a configured schedule, and it even supports a simple "cron job" syntax. I've had a lot of success with it.
Here's a quick example of its usage:
// Instantiate the Quartz.NET scheduler
var schedulerFactory = new StdSchedulerFactory();
var scheduler = schedulerFactory.GetScheduler();
// Instantiate the JobDetail object passing in the type of your
// custom job class. Your class merely needs to implement a simple
// interface with a single method called "Execute".
var job = new JobDetail("job1", "group1", typeof(MyJobClass));
// Instantiate a trigger using the basic cron syntax.
// This tells it to run at 1AM every Monday - Friday.
var trigger = new CronTrigger(
"trigger1", "group1", "job1", "group1", "0 0 1 ? * MON-FRI");
// Add the job to the scheduler
scheduler.AddJob(job, true);
scheduler.ScheduleJob(trigger);
A daily task? Sounds like it should just be a scheduled task (control panel) - no need for a service here.
Does it have to be an actual service? Can you just use the built in scheduled tasks in the windows control panel.
The way I accomplish this is with a timer.
Run a server timer, have it check the Hour/Minute every 60 seconds.
If it's the right Hour/Minute, then run your process.
I actually have this abstracted out into a base class I call OnceADayRunner.
Let me clean up the code a bit and I'll post it here.
private void OnceADayRunnerTimer_Elapsed(object sender, ElapsedEventArgs e)
{
using (NDC.Push(GetType().Name))
{
try
{
log.DebugFormat("Checking if it's time to process at: {0}", e.SignalTime);
log.DebugFormat("IsTestMode: {0}", IsTestMode);
if ((e.SignalTime.Minute == MinuteToCheck && e.SignalTime.Hour == HourToCheck) || IsTestMode)
{
log.InfoFormat("Processing at: Hour = {0} - Minute = {1}", e.SignalTime.Hour, e.SignalTime.Minute);
OnceADayTimer.Enabled = false;
OnceADayMethod();
OnceADayTimer.Enabled = true;
IsTestMode = false;
}
else
{
log.DebugFormat("Not correct time at: Hour = {0} - Minute = {1}", e.SignalTime.Hour, e.SignalTime.Minute);
}
}
catch (Exception ex)
{
OnceADayTimer.Enabled = true;
log.Error(ex.ToString());
}
OnceADayTimer.Start();
}
}
The beef of the method is in the e.SignalTime.Minute/Hour check.
There are hooks in there for testing, etc. but this is what your elapsed timer could look like to make it all work.
As others already wrote, a timer is the best option in the scenario you described.
Depending on your exact requirements, checking the current time every minute may not be necessary.
If you do not need to perform the action exactly at midnight, but just within one hour after midnight, you can go for Martin's approach of only checking if the date has changed.
If the reason you want to perform your action at midnight is that you expect a low workload on your computer, better take care: The same assumption is often made by others, and suddenly you have 100 cleanup actions kicking off between 0:00 and 0:01 a.m.
In that case you should consider starting your cleanup at a different time. I usually do those things not at clock hour, but at half hours (1.30 a.m. being my personal preference)
I would suggest that you use a timer, but set it to check every 45 seconds, not minute. Otherwise you can run into situations where with heavy load, the check for a particular minute is missed, because between the time the timer triggers and the time your code runs and checks the current time, you might have missed the target minute.
You can also try the TaskSchedulerLibrary here http://visualstudiogallery.msdn.microsoft.com/a4a4f042-ffd3-42f2-a689-290ec13011f8
Implement the abstract class AbstractScheduledTask and call the ScheduleUtilityFactory.AddScheduleTaskToBatch static method
For those that found the above solutions not working, it's because you may have a this inside your class, which implies an extension method which, as the error message says, only makes sense on a non-generic static class. Your class isn't static. This doesn't seem to be something that makes sense as an extension method, since it's acting on the instance in question, so remove the this.
Try this:
public partial class Service : ServiceBase
{
private Timer timer;
public Service()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
SetTimer();
}
private void SetTimer()
{
if (timer == null)
{
timer = new Timer();
timer.AutoReset = true;
timer.Interval = 60000 * Convert.ToDouble(ConfigurationManager.AppSettings["IntervalMinutes"]);
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Start();
}
}
private void timer_Elapsed(object source, System.Timers.ElapsedEventArgs e)
{
//Do some thing logic here
}
protected override void OnStop()
{
// disposed all service objects
}
}

Quick while stopping

i have this code:
private STOP = false;
public void Start()
{
while(!STOP)
{
//do some work
Thread.Sleep(15000);
}
}
public void Stop()
{
STOP = true;
}
But using this code sometimes need to wait a 15 secs, how to quickly stop this cycle or maybe need to use other code?
Thanks!
Something along the lines of:
private System.Threading.ManualResetEvent STOP = new System.Threading.ManualResetEvent(false);
public void Start()
{
while(true)
{
//do some work
if(STOP.WaitOne(15000))
break;
}
}
public void Stop()
{
STOP.Set();
}
Whenever you find yourself writing a loop that does something, then waits a relatively long period of time (even one second is a long time!) to do it again, you should eliminate the loop and use a timer. For example, your code above can be re-written:
System.Threading.Timer MyTimer;
public void Start()
{
MyTimer = new Timer((s) =>
{
DoSomeWork();
}, null, 15000, 15000);
}
The timer will be triggered every 15 seconds to do the work. When it's time to shut down the program, just dispose of the timer.
public void Stop()
{
MyTimer.Dispose();
}
This will be more efficient than using a separate thread that spends most of its time sleeping, but still consuming system resources.
Use ManualResetEvent.WaitOne with timeout.
manualResetEvent.WaitOne(timeout)
Set the event to wake it up, or it will wake up when timed out.
See this related question.

Single threaded timer

I wanted a timer with the following properties:
No matter how many times start is called, only one call back thread is ever running
The time spent in the call back function was ignored with regards to the interval. E.g if the interval is 100ms and the call back takes 4000ms to execute, the callback is called at 100ms, 4100ms etc.
I couldn't see anything available so wrote the following code. Is there a better way to do this?
/**
* Will ensure that only one thread is ever in the callback
*/
public class SingleThreadedTimer : Timer
{
protected static readonly object InstanceLock = new object();
//used to check whether timer has been disposed while in call back
protected bool running = false;
virtual new public void Start()
{
lock (InstanceLock)
{
this.AutoReset = false;
this.Elapsed -= new ElapsedEventHandler(SingleThreadedTimer_Elapsed);
this.Elapsed += new ElapsedEventHandler(SingleThreadedTimer_Elapsed);
this.running = true;
base.Start();
}
}
virtual public void SingleThreadedTimer_Elapsed(object sender, ElapsedEventArgs e)
{
lock (InstanceLock)
{
DoSomethingCool();
//check if stopped while we were waiting for the lock,
//we don't want to restart if this is the case..
if (running)
{
this.Start();
}
}
}
virtual new public void Stop()
{
lock (InstanceLock)
{
running = false;
base.Stop();
}
}
}
Here's a quick example I just knocked up;
using System.Threading;
//...
public class TimerExample
{
private System.Threading.Timer m_objTimer;
private bool m_blnStarted;
private readonly int m_intTickMs = 1000;
private object m_objLockObject = new object();
public TimerExample()
{
//Create your timer object, but don't start anything yet
m_objTimer = new System.Threading.Timer(callback, m_objTimer, Timeout.Infinite, Timeout.Infinite);
}
public void Start()
{
if (!m_blnStarted)
{
lock (m_objLockObject)
{
if (!m_blnStarted) //double check after lock to be thread safe
{
m_blnStarted = true;
//Make it start in 'm_intTickMs' milliseconds,
//but don't auto callback when it's done (Timeout.Infinite)
m_objTimer.Change(m_intTickMs, Timeout.Infinite);
}
}
}
}
public void Stop()
{
lock (m_objLockObject)
{
m_blnStarted = false;
}
}
private void callback(object state)
{
System.Diagnostics.Debug.WriteLine("callback invoked");
//TODO: your code here
Thread.Sleep(4000);
//When your code has finished running, wait 'm_intTickMs' milliseconds
//and call the callback method again,
//but don't auto callback (Timeout.Infinite)
m_objTimer.Change(m_intTickMs, Timeout.Infinite);
}
}
The .NET Framework provides four timers. Two of these are general-purpose multithreaded
timers:
System.Threading.Timer
System.Timers.Timer
The other two are special-purpose single-threaded timers:
System.Windows.Forms.Timer (Windows Forms timer)
System.Windows.Threading.DispatcherTimer (WPF timer)
The last 2 are designed to eliminate thread-safety issues for WPF and Windows Forms applications.
For example, using WebBrowser inside a timer to capture screenshots from webpage needs to be single-threaded and gives an error at runtime if it is on another thread.
The single-thread timers have the following benefits
You can forget about thread safety.
A fresh Tick will never fire until the previous Tick has finished
processing.
You can update user interface elements and controls directly from
Tick event handling code, without calling Control.BeginInvoke or
Dispatcher.BeginIn voke.
and main disadvantage to note
One thread serves all timers—as well as the processing UI events.
Which means that the Tick event handler must execute quickly,
otherwise the user interface becomes unresponsive.
source: most are scraps from C# in a Nutshell book -> Chapter 22 -> Advanced threading -> Timers -> Single-Threaded Timers
For anyone who needs a single thread timer and wants the timer start to tick after task done.
System.Timers.Timer could do the trick without locking or [ThreadStatic]
System.Timers.Timer tmr;
void InitTimer(){
tmr = new System.Timers.Timer();
tmr.Interval = 300;
tmr.AutoReset = false;
tmr.Elapsed += OnElapsed;
}
void OnElapsed( object sender, System.Timers.ElapsedEventArgs e )
{
backgroundWorking();
// let timer start ticking
tmr.Enabled = true;
}
Credit to Alan N
source https://www.codeproject.com/Answers/405715/System-Timers-Timer-single-threaded-usage#answer2
Edit: spacing
Look at the [ThreadStatic] attribute and the .Net 4.0 ThreadLocal generic type. This will probably quickly give you a way to code this without messing with thread locking etc.
You could have a stack inside your time class, and you could implement a Monitor() method that returns a IDisposable, so you can use the timer like so:
using (_threadTimer.Monitor())
{
// do stuff
}
Have the timer-monitor pop the the interval timestamp off the stack during Dispose().
Manually coding all the locking and thread recognition is an option as has been mentioned. However, locking will influence the time used, most likely more than having to initialize an instance per thread using ThreadLocal
If you're interested, I might knock up an example later
Here is a simple PeriodicNonOverlappingTimer class, that provides just the requested features, and nothing more than that. This timer cannot be started and stopped on demand, and neither can have its interval changed. It just invokes the specified action periodically in a non overlapping manner, until the timer is disposed.
/// <summary>
/// Invokes an action on the ThreadPool at specified intervals, ensuring
/// that the invocations will not overlap, until the timer is disposed.
/// </summary>
public class PeriodicNonOverlappingTimer : IDisposable, IAsyncDisposable
{
private readonly System.Threading.Timer _timer;
public PeriodicNonOverlappingTimer(Action periodicAction,
TimeSpan dueTime, TimeSpan period)
{
// Arguments validation omitted
_timer = new(_ =>
{
var stopwatch = Stopwatch.StartNew();
periodicAction();
var nextDueTime = period - stopwatch.Elapsed;
if (nextDueTime < TimeSpan.Zero) nextDueTime = TimeSpan.Zero;
try { _timer.Change(nextDueTime, Timeout.InfiniteTimeSpan); }
catch (ObjectDisposedException) { } // Ignore this exception
});
_timer.Change(dueTime, Timeout.InfiniteTimeSpan);
}
public void Dispose() => _timer.DisposeAsync().AsTask().Wait();
public ValueTask DisposeAsync() => _timer.DisposeAsync();
}
Usage example. Shows how to create a non-overlapping timer that starts immediately, with a period of 10 seconds.
var timer = new PeriodicNonOverlappingTimer(() =>
{
DoSomethingCool();
}, TimeSpan.Zero, TimeSpan.FromSeconds(10));
//...
timer.Dispose(); // Stop the timer once and for all
In case the DoSomethingCool fails, the exception will be thrown on the ThreadPool, causing the process to crash. So you may want to add a try/catch block, and handle all the exceptions that may occur.
The Dispose is a potentially blocking method. If the periodicAction is currently running, the Dispose will block until the last invocation is completed.
If you don't want to wait for this to happen, you can do this instead:
_ = timer.DisposeAsync(); // Stop the timer without waiting it to finish

Non-reentrant C# timer

I'm trying to invoke a method f() every t time, but if the previous invocation of f() has not finished yet, wait until it's finished.
I've read a bit about the available timers but couldn't find any good way of doing what I want, save for manually writing it all. Any help about how to achieve this will be appreciated, though I fear I might not be able to find a simple solution using timers.
To clarify, if t is one second, and f() runs the arbitrary durations I've written below, then:
Step Operation Time taken
1 wait 1s
2 f() 0.6s
3 wait 0.4s (because f already took 0.6 seconds)
4 f() 10s
5 wait 0s (we're late)
6 f() 0.3s
7 wait 0.7s (we can disregard the debt from step 4)
Notice that the nature of this timer is that f() will not need to be safe regarding re-entrance, and a thread pool of size 1 is enough here.
Use a System.Threading.Timer. Initialize it with a period of Timeout.Infinite so it acts like a one-shot timer. When f() completes, call its Change() method to recharge it again.
You could just use a 'global' level var (or more likely, a public property in the same class as f()) which returns true if f() is already running.
So if f() was in a class named TimedEvent, the first thing f() would do is set Running true
That way your timer fires every second, then launches the timed event if it isnt already running
if (!timedEvent.Running) timedEvent.f()
You commented that f() wouldnt repeat immediately if it took longer than the timer interval. Thats a fair point. I would probably include logic like that inside f() so that Running stays true. So it would look something like this:
public void f(int t) // t is interval in seconds
{
this.running = true;
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
do
{
stopwatch.Reset();
// Do work here
} while (stopWatch.Elapsed.Seconds > t); // repeat if f() took longer than t
this.running = false;
}
You can use a non-restarting timer, then manually restart the timer after the method finishes.
Note that this will result in timing that is somewhat different from what you're asking for. (There will always be a gap of t time between invocations)
You could solve that by setting the interval to lastTick + t - Now, and running the method immediately if that's <= 0.
Beware of race conditions if you need to stop the timer.
You cannot get a timer to call you at exactly scheduled intervals. All timers do is call you back no sooner than the requested time.
Some timers are better than others (e.g. Windows.Forms.Timer is very erratic and unreliable compared to System.Threading.Timer)
To stop your timer being called re-entrantly, one approach is to Stop the timer while your method is running. (Depending on the type of timer you use, you either stop it and start it again when your handler exits, or with some timers you can request a single callback rather than repeating callbacks, so each execution of your handler simply enqueues the next call).
To keep the timing relatively even between these calls you can record the time since your handler last executed and use that to calculate the delay until the next event is required. e.g. If you want to be called once per second and your timer completed provcessing at 1.02s, then you can set up the next timer callback at a duration of 0.98s to accomodate the fact that you've already "used up" part of the next second during your processing.
A straightforward solution:
private class Worker : IDisposable
{
private readonly TimeSpan _interval;
private WorkerContext _workerContext;
private sealed class WorkerContext
{
private readonly ManualResetEvent _evExit;
private readonly Thread _thread;
private readonly TimeSpan _interval;
public WorkerContext(ParameterizedThreadStart threadProc, TimeSpan interval)
{
_evExit = new ManualResetEvent(false);
_thread = new Thread(threadProc);
_interval = interval;
}
public ManualResetEvent ExitEvent
{
get { return _evExit; }
}
public TimeSpan Interval
{
get { return _interval; }
}
public void Run()
{
_thread.Start(this);
}
public void Stop()
{
_evExit.Set();
}
public void StopAndWait()
{
_evExit.Set();
_thread.Join();
}
}
~Worker()
{
Stop();
}
public Worker(TimeSpan interval)
{
_interval = interval;
}
public TimeSpan Interval
{
get { return _interval; }
}
private void DoWork()
{
/* do your work here */
}
public void Start()
{
var context = new WorkerContext(WorkThreadProc, _interval);
if(Interlocked.CompareExchange<WorkerContext>(ref _workerContext, context, null) == null)
{
context.Run();
}
else
{
context.ExitEvent.Close();
throw new InvalidOperationException("Working alredy.");
}
}
public void Stop()
{
var context = Interlocked.Exchange<WorkerContext>(ref _workerContext, null);
if(context != null)
{
context.Stop();
}
}
private void WorkThreadProc(object p)
{
var context = (WorkerContext)p;
// you can use whatever time-measurement mechanism you want
var sw = new System.Diagnostics.Stopwatch();
int sleep = (int)context.Interval.TotalMilliseconds;
while(true)
{
if(context.ExitEvent.WaitOne(sleep)) break;
sw.Reset();
sw.Start();
DoWork();
sw.Stop();
var time = sw.Elapsed;
if(time < _interval)
sleep = (int)(_interval - time).TotalMilliseconds;
else
sleep = 0;
}
context.ExitEvent.Close();
}
public void Dispose()
{
Stop();
GC.SuppressFinalize(this);
}
}
How about using delegates to method f(), queuing them to a stack, and popping the stack as each delegate completes? You still need the timer, of course.
A simple thread is the easiest way to achieve this. Your still not going to be certain that your called 'precisely' when you want, but it should be close.... Also you can decide if you want to skip calls that should happen or attempt to catch back up... Here is simple helper routine for creating the thread.
public static Thread StartTimer(TimeSpan interval, Func<bool> operation)
{
Thread t = new Thread(new ThreadStart(
delegate()
{
DateTime when = DateTime.Now;
TimeSpan wait = interval;
while (true)
{
Thread.Sleep(wait);
if (!operation())
return;
DateTime dt = DateTime.Now;
when += interval;
while (when < dt)
when += interval;
wait = when - dt;
}
}
));
t.IsBackground = true;
t.Start();
return t;
}
For the benefit of people who land here searching for "re-entrancy": (I know this may be too late for the original question)
If one is not averse to using open source libraries that already provide for such functionality, I have successfully achieved this through an implementation using Quartz.NET
When you create a job and attach a trigger, you can specify what should be done if a previous trigger has not completed executing it's job

C# killing a thread

In my app, I have a thread that runs continuously. By using Thread.Sleep(), the function executes every 10 minutes.
I need to be able to kill this thread when a user clicks a button. I know Thread.Abort() is not reliable. I can use a variable to stop the thread, but since it is sleeping it could be another 10 minutes before the thread kills itself.
Any ideas?
Why don't you use a timer to schedule the task every ten minutes instead. That will run your code on a thread pool thread and thus you will not have to manage this yourself.
For more details see the System.Threading.Timer class.
Instead of Thread.Sleep use a System.Threading.ManualResetEvent. The WaitOne method has a timeout just like Thread.Sleep, your thread will sleep for that interval unless the event is triggered first, and the return value tells you whether the interval elapsed or the event was set.
So here's a sample that users timers to do the work as suggested by Brian. Use start/stop as needed. To cleanup the (Program) object once you are done with it make sure you call Dispose.
Just note that when you call Stop it will prevent the timer from firing again, however you still may have a worker thread in the middle of executing the timer_Elapsed handler, i.e. stopping the timer doesn't stop any currently executing worker thread.
using System;
using System.Timers;
namespace TimerApp
{
class Program : IDisposable
{
private Timer timer;
public Program()
{
this.timer = new Timer();
this.timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
this.timer.AutoReset = true;
this.timer.Interval = TimeSpan.FromMinutes(10).TotalMilliseconds;
}
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
// TODO...your periodic processing, executed in a worker thread.
}
static void Main(string[] args)
{
// TODO...your app logic.
}
public void Start()
{
this.timer.Start();
}
public void Stop()
{
this.timer.Stop();
}
public void Dispose()
{
this.timer.Dispose();
}
}
}
Building on Ben's answer, here's the pattern to help you out...
using System.Threading;
public class MyWorker {
private ManualResetEvent mResetEvent = new ManualResetEvent(false);
private volatile bool mIsAlive;
private const int mTimeout = 6000000;
public void Start()
{
if (mIsAlive == false)
{
mIsAlive = true;
Thread thread = new Thread(new ThreadStart(RunThread));
thread.Start();
}
}
public void Stop()
{
mIsAlive = false;
mResetEvent.Set();
}
public void RunThread()
{
while(mIsAlive)
{
//Reset the event -we may be restarting the thread.
mResetEvent.Reset();
DoWork();
//The thread will block on this until either the timeout
//expires or the reset event is signaled.
if (mResetEvent.WaitOne(mTimeout))
{
mIsAlive = false; // Exit the loop.
}
}
}
public void DoWork()
{
//...
} }
One possibility is to not have it sleep for ten minutes. Have it sleep for 10 seconds then only do its work on every sixtieth wakeup. Then you only have a latency of ten seconds before it stops.
Aside: This is not necessarily the best solution but it's probably the quickest to implement. As with all possibilities you should do a cost/benefit analysis when selecting which solution is right for you.
If ten seconds is still too much, you can drop it further although keep in mind that dropping it too far will result in a possible performance impact.
You're right that you shouldn't kill threads from outside, it's usually a recipe for disaster if you happen to do it while they have a lock on some resource that's not freed on kill. Threads should always be responsible for their own resources, including their lifetimes.

Categories

Resources