I am currently using this preliminary approach:
public class AskingForWorkClass
{
private static Timer _timer;
public void Start()
{
// catchup with outstanding work
DoWork(this, null);
_timer = new Timer { Interval = 1000 }; // one second
_timer.Elapsed += DoWork;
_timer.Start();
}
private void DoWork(object sender, EventArgs e)
{
}
}
The intention is that when Start is invoked all outstanding work is done first. After that a timer is used to invoke DoWork, which checks for more work does it. Please note that I would like to prevent DoWork from being hit by the timer if it is still running from the last invocation by the timer. Is this possible? Basically, DoWork should only be run by one process at the time.
You can just start / stop the timer in your DoWork method:
private void DoWork(object sender, EventArgs e)
{
_timer.Stop();
// .. do stuff ...
_timer.Start();
}
Note: depending on which Timer class you're using, you may not have Start and Stop and instead need to use the Modify method, but you get the idea.
UPDATE
So based on comments this is a solution which should prevent any incident of DoWork executing twice, regardless of the Interval property.
public class AskingForWorkClass
{
private static Timer _timer;
private AutoResetEvent _event = new AutoResetEvent(true);
public void Start()
{
// catchup with outstanding work
DoWork(this, null);
_timer = new Timer { Interval = 1000 }; // one second
_timer.Elapsed += DoWork;
_timer.Start();
}
private void DoWork(object sender, EventArgs e)
{
_event.WaitOne();
// ... do stuff here ...
_event.Set();
}
}
What happens here is that that when DoWork is entered it will wait until the event has been set to the signaled state and block the current thread until that happens. Note that the construction of the event new AutoResetEvent(true) creates the event in the signaled state so the first time DoWork is called it doesn't block forever.
Once the WaitOne call passes, the event automatically sets itself back to the unsignaled state meaning that future calls to the DoWork method will be blocked. Then finally we call the Set method which puts the event back into the signaled state until the next WaitOne call.
Related
As title says, I'm currently making a WPF application and I need to detect if an application is running and do something when it's closed. The way I'd thought of doing so is by running a separate Thread and checking every two seconds if the process is still running, something like this:
while(Process.GetProcessesByName(processName).Length != 0) {
Thread.Sleep(2000);
}
//Do something
Would this be a good solution, is there any other way of doing this?
Thanks
Would this be a good solution?
No, because it would waste an entire thread for nearly nothing.
Better use a timer, in a WPF application preferrably a DispatcherTimer:
var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(2) };
timer.Tick += (s, e) =>
{
if (Process.GetProcessesByName(processName).Length > 0)
{
// ...
}
};
timer.Start();
If there would be a lengthy operation to be performed off the UI thread, you could use an async Tick event handler that awaits a Task (which would run on a thread pool thread in the background):
var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(2) };
timer.Tick += async (s, e) =>
{
if (Process.GetProcessesByName(processName).Length > 0)
{
await Task.Run(() =>
{
// lengthy operation here which runs on a thread pool thread
});
// udate UI here
}
};
timer.Start();
Since you are already dealing with Processes, I would suggest just using it directly to determine if it has exited. You can use the Exited event handler for your code. So, for instance:
foreach (var process in Process.GetProcessesByName(processName))
{
process.Exited += new EventHandler(DoSomething);
}
…
public void DoSomething(object sender, System.EventArgs e)
{
// do something
}
This will call DoSomething when the process with that name ends.
You could use a System.Timers.Timer that performs the check every x seconds:
public sealed partial class Window1 : Window, IDisposable
{
private readonly System.Timers.Timer _timer = new System.Timers.Timer(TimeSpan.FromSeconds(2).TotalMilliseconds);
public Window1()
{
InitializeComponent();
_timer.Elapsed += _timer_Elapsed;
_timer.Start();
}
private void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (Process.GetProcessesByName("processName...").Length == 0)
{
_timer.Stop();
_timer.Dispose();
//do something...
}
}
public void Dispose()
{
_timer.Dispose();
}
}
Unlike the Tick event of a DispatcherTimer, the Elapsed event of a Timer is always queued for execution on a thread pool thread.
From the docs:
If a System.Timers.Timer is used in a WPF application, it is worth noting that the System.Timers.Timer runs on a different thread than the user interface (UI) thread...Reasons for using a DispatcherTimer as opposed to a System.Timers.Timer are that the DispatcherTimer runs on the same thread as the Dispatcher and a DispatcherPriority can be set on the DispatcherTimer.
I want to raise a function periodically .
When I finish one function cycle to wait some period of time and only them to start the second run.
I thought to make it like :
timer = new System.Timers.Timer();
timer.Interval = 1000;
timer.Enabled = true;
timer.Start();
timer.Elapsed += TimerTick;
private void TimerTick(object sender, EventArgs e)
{
//My functionality
}
But seems that TimerTick is raised every secound and not secound from my last TimerTick run .
How i can solve this one ?
You can use threads:
var thread = new Thread(o => {
while(true)
{
DoTick();
Thread.Sleep(1000);
}
});
You can stop your timer before doing your processing and start it again after it's done:
private void TimerTick(object sender, EventArgs e)
{
timer.Stop();
//My functionality
timer.Start();
}
it's also a good idea to put your functionality in a try-catch and call Start() in the finally section. (if this suits you)
Try the following:
private void TimerTick(object sender, EventArgs e)
{
// get the timer that raised this event (you can have multiple
// timers, or the timer obj is out of scope here, so use this):
Timer timer = (Timer) sender;
// disable (or use timer.Stop())
timer.Enabled = false;
// ...
// your code
// ...
// at end, re-enable
timer.Enabled = true;
}
you will find that the timer will now run 1000ms after your code finished. You can also use timer.Stop() and timer.Start().
you could always do something like this:
while (true)
{
// your functions
Thread.Sleep(1000)
}
you'd have to find a way to stop this through an external mechanism, but it should work.
You're right: the timer will run every second: it won't care what you're doing in the TimerTick.
What you can do is to stop the timer on entering the TimerTick methode.
private void TimerTick(object sender, EventArgs e)
{
timer.Stop();
//My functionality
timer.Start();
}
Try this:
DateTime lastDT = DateTime.MinValue;
private void TimerTick(object sender, EventArgs e)
{
DateTime now = DateTime.Now;
if (now - last).TotalSeconds > what_you_want
{
//My functionality
}
last = now;
}
Using this, your form (main thread) is not locked and you/user can do what you please.
Try
private void TimerTick(object sender, EventArgs e)
{
timer.Stop();
// My Functionality
timer.Stop();
}
However, you may have an extra even fired. As per MSDN Docs:
The signal to raise the Elapsed event is always queued for execution on a ThreadPool thread, so the event-handling method might run on one thread at the same time that a call to the Stop method runs on another thread. This might result in the Elapsed event being raised after the Stop method is called. The code example in the next section shows one way to work around this race condition.
You might want to consider Thread.Sleep() instead
I want to call the timer callback just one time until it finishes the task. For example if the timer interval is five minutes and the task may be done within 2-20 minutes, if the previous task is not completed, new threads doesn't enter callback method.
Currently I do this by a volatile counter but it doesn't make sense to me. There should be a best practice. Sample code:
private volatile int _counter = 0;
private readonly object _syncLock = new object();
void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
lock(syncLock)
{
if (_counter > 0)
return;
else
Interlocked.Increment(ref _counter);
}
// Method body
Interlocked.Decrement(ref _counter);
}
This one is simple enough actually. When you initialize the timer set the AutoReset property to false.
_timer.AutoReset = false;
Then at the end of your event handler invoke this:
_timer.Start();
How do I get a timer event to fire one at a time.
For example I have a timer that raises an event every 10 minutes.
The event that is raised takes 10 or more minutes to finish executing.
I would like the timer to reset AFTER the event has finished.
In other words I do not want to raise more than 1 instance of the event at any one time.
Use System.Timers.Timer not the Threading one
Set AutoReset to false.
Then Start it again when you're done.
Usually what I do is have my event stop the timer when it's raised and then restart the timer when the event process completes:
private void timerHandler(object sender, TimerElapsedEventArgs e)
{
Timer timer = (Timer)sender;
timer.Stop();
RunProcess();
timer.Start();
}
public void RunProcess()
{
/* Do stuff that takes longer than my timer interval */
}
Now my timer will start again on completion of the process
It may be difficult to stop timers for efficiency or logic. The following code synchronizes skipping the events.
static readonly object key = new object();
void TimerHandler(object sender, TimerElapsedEventArgs e)
{
if(Monitor.TryEnter(key))
{
try
{
//do your stuff
}
finally
{
Montitor.Exit(key);
}
}
}
I have a timer that needs to not process its elapsed event handler at the same time. But processing one Elapsed event may interfere with others. I implemented the below solution, but something feels wrong; it seems like either I should be using the timer differently or using another object within the threading space. The timer seemed to fit best because I do need to periodically check for a status, but sometimes checking will take longer than my interval. Is this the best way to approach this?
// member variable
private static readonly object timerLock = new object();
private bool found = false;
// elsewhere
timer.Interval = TimeSpan.FromSeconds(5).TotalMilliseconds;
timer.Elapsed = Timer_OnElapsed;
timer.Start();
public void Timer_OnElapsed(object sender, ElapsedEventArgs e)
{
lock(timerLock)
{
if (!found)
{
found = LookForItWhichMightTakeALongTime();
}
}
}
You could set AutoReset to false, then explicitly reset the timer after you are done handling it. Of course, how you handle it really depends on how you expect the timer to operate. Doing it this way would allow your timer to drift away from the actual specified interval (as would stopping and restarting). Your mechanism would allow each interval to fire and be handled but it may result in a backlog of unhandled events that are handled now where near the expiration of the timer that cause the handler to be invoked.
timer.Interval = TimeSpan.FromSeconds(5).TotalMilliseconds;
timer.Elapsed += Timer_OnElapsed;
timer.AutoReset = false;
timer.Start();
public void Timer_OnElapsed(object sender, ElapsedEventArgs e)
{
if (!found)
{
found = LookForItWhichMightTakeALongTime();
}
timer.Start();
}
I usually stop the timer while processing it, enter a try/finally block, and resume the timer when done.
If LookForItWhichMightTakeALongTime() is going to take a long time, I would suggest not using a System.Windows.Forms.Timer because doing so will lock up your UI thread and the user may kill your application thinking that it has frozen.
What you could use is a BackgroundWorker (along with a Timer if so desired).
public class MyForm : Form
{
private BackgroundWorker backgroundWorker = new BackgroundWorker();
public MyForm()
{
InitializeComponents();
backgroundWorker.DoWork += backgroundWorker_DoWork;
backgroundWorker.RunWorkerCompleted +=
backgroundWorker_RunWorkerCompleted;
backgroundWorker.RunWorkerAsync();
}
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
e.Result = LookForItWhichMightTakeALongTime();
}
private void backgroundWorker_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
found = e.Result as MyClass;
}
}
And you can call RunWorkerAsync() from anywhere you want to, even from a Timer if you want. And just make sure to check if the BackgroundWorker is running already since calling RunWorkerAsync() when it's running will throw an exception.
private void timer_Tick(object sender, EventArgs e)
{
if (!backgroundWorker.IsBusy)
backgroundWorker.RunWorkerAsync();
}
timer.enabled = false
or
timer.stop();
and
timer.enabled = true
or
timer.start();
I use the System.Threading.Timer like so
class Class1
{
static Timer timer = new Timer(DoSomething,null,TimeSpan.FromMinutes(1),TimeSpan.FromMinutes(1));
private static void DoSomething(object state)
{
timer = null; // stop timer
// do some long stuff here
timer = new Timer(DoSomething, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));
}
}