Reset System.Timers.Timer to prevent Elapsed event - c#

I am trying to use the Timer to trigger an event to send data across the network. I created a simple class to debug. Basically I have a List<string> I'd like to send. I want the following to happen:
Add string to List
Start Timer for 10 seconds
Add second string to List before Timer.Elapsed
Restart Timer back at 10 seconds.
So far I have this:
public static List<string> list;
public static Timer timer;
public static bool isWiredUp = false;
public static void Log(string value) {
if (list == null) list = new List<string>();
list.Add(value);
//this does not reset the timer, elapsed still happens 10s after #1
if (timer != null) {
timer = null;
}
timer = new Timer(10000);
timer.Start();
timer.Enabled = true;
timer.AutoReset = false;
if (!isWiredUp) {
timer.Elapsed += new ElapsedEventHandler(SendToServer);
isWiredUp = true;
}
}
static void SendToServer(object sender, ElapsedEventArgs e) {
timer.Enabled = false;
timer.Stop();
}
Any ideas?

You can use the Stop function followed immediately by the Start function to "restart" the timer. Using that you can create the Timer when the class is first created, wire up the Elapsed event at that time, and then do nothing but call those two methods when an item is added. It will either start, or restart, the timer. Note that calling Stop on a timer that hasn't yet been started just does nothing, it doesn't throw an exception or cause any other problems.
public class Foo
{
public static List<string> list;
public static Timer timer;
static Foo()
{
list = new List<string>();
timer = new Timer(10000);
timer.Enabled = true;
timer.AutoReset = false;
timer.Elapsed += SendToServer;
}
public static void Log(string value)
{
list.Add(value);
timer.Stop();
timer.Start();
}
static void SendToServer(object sender, ElapsedEventArgs e)
{
//TODO send data to server
//AutoReset is false, so neither of these are needed
//timer.Enabled = false;
//timer.Stop();
}
}
Note that rather than using a List it's very possible that you want to use a BlockingCollection<string> instead. This has several advantages. First, the Log methods will work if called at the same time from multiple threads; as is multiple concurrent logs could break the list. It also means that SendToServer can be taking items out of the queue at the same time that new items are added. If you use a List you'll need to lock all access to the list (which might not be a problem, but isn't as straightforward).

This kind of thing is very easy to achieve with IObservable (Rx).
Let us simplify matters by declaring a Subject<string> as your list to push onto using .OnNext. Once you have your subject, an observable, you can do what you want with a single 'line' of System.Reactive.Linq. This is illustrated in the following pseudo-c#
subject
.Buffer(<your timespan>,1) //buffer until either a value is added or the timeout expires
.Subscribe(x =>
{
if (x.Count == 0) //the timeout expired so send on
{
SendAccumulatedListToServer(<your list>);
<clear your list>
}
else
{
<your list>.Add(x);
}
});

What you are implementing is totally the wrong way to go about doing this. Have a look at the consumer producer model:
http://msdn.microsoft.com/en-us/library/hh228601.aspx
What you are trying to do is very commonly called the Consumer/Producer dataflow model. Essentially you have something generating a list of data that is to be sent somewhere, rather than sending it each time an item is added to the list you would like to send them in groups.. So you have a producer (the code putting data to be sent) and a consumer (the code sending the data).
Generally this problem is solved by spawning a thread that watches the list (usually a queue) and sends the data at regulary intervals, the best way to do this is using an EventWaitHandle.
Here is some very simplified code as an example
class ServerStuff
{
public void Init()
{
datatosend = new List<string>();
exitrequest = new EventWaitHandle(false, EventResetMode.ManualReset); //This wait handle will signal the consumer thread to exit
Thread t = new Thread(new ThreadStart(_RunThread));
t.Start(); // Start the consumer thread...
}
public void Stop()
{
exitrequest.Set();
}
List<string> datatosend;
EventWaitHandle exitrequest;
public void AddItem(string item)
{
lock (((ICollection)datatosend).SyncRoot)
datatosend.Add(item);
}
private void RunThread()
{
while (exitrequest.WaitOne(10 * 1000)) //wait 10 seconds between sending data, or wake up immediatly to exit request
{
string[] tosend;
lock (((ICollection)datatosend).SyncRoot)
{
tosend = datatosend.ToArray();
datatosend.Clear();
}
//Send the data to Sever here...
}
}
}

Related

How To: stagger SignalR Clients.Others.[function] calls in C#

I have a basic function that looks like this:
public void AllDataUpdated()
{
Clients.Others.allDataUpdated();
}
Now, I want to add a half-second delay between each of these calls. But, I don't want to just lock my web-server up in doing so.
My first instinct was to do the following:
async Task SendWithDelay(var other, var timeout)
{
await Task.Delay(timeout);
other.allDataUpdated();
}
and iterate over each other in my public void AllDataUpdated() function and increment the timeout for each iteration. Is this the correct approach? How should I do this in a manner that will not lock-up my webserver with this process, but will stagger the SignalR emits?
Thanks!
EDIT: My desired result is that client_0 gets this message at 0ms, then client_1 gets the message at 500ms, etc. All from the same call to AllDataUpdated().
// synchronization primitive
private readonly object syncRoot = new object();
// the timer for 500 miliseconds delay
private Timer notificator;
// public function used for notification with delay
public void NotifyAllDataUpdatedWithDelay() {
// first, we need claim lock, because of accessing from multiple threads
lock(this.syncRoot) {
if (null == notificator) {
// notification timer is lazy-loaded
notificator = new Timer(500);
notificator.Elapse += notificator_Elapsed;
}
if (false == notificator.Enabled) {
// timer is not enabled (=no notification is in delay)
// enabling = starting the timer
notificator.Enabled = true;
}
}
}
private void notificator_Elapsed(object sender, ElapsedEventArgs e) {
// first, we need claim lock, because of accessing from multiple threads
lock(this.syncRoot) {
// stop the notificator
notificator.Enabled = false;
}
// notify clients
Clients.Others.allDataUpdated();
}

Calling a method after set amount of time and/or aborting thread issues

So I've got an application that employs a filesystemWatcher and triggers an event just fine. The FSW will trigger a bunch of times pretty close together. I want to create a function that triggers say an hour after the last time the FSW was triggered.
I first tried using a backgroundworker: (All code is shortened for clarity)
namespace Devo
{
public partial class Form1 : Form
{
BackgroundWorker bw = new BackgroundWorker();
private void fileSystemWatcher_Created(object sender, FileSystemEventArgs e)
{
if (bw.IsBusy)
{
bw.CancelAsync(); //this is to, in a way, reset the timer for the delayed method.
}
//do a lot of stuff
bw.RunWorkerAsync();
}
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
Stopwatch sw = new Stopwatch();
sw.Start();
while(sw.ElapsedMilliseconds < 180000)
{
if (bw.CancellationPending == true)
{
sw.Stop();
sw.Reset();
e.Cancel = true;
return;
}
}
sw.Stop();
sw.Reset();
DelayedMethod();
}
}
}
This didn't work as the second time bw.RunWorkerAsync() was called it was apparently busy, even though the call to bw.CancelAsync().
My next attempt involved a regular thread as I read somewhere on SO (can't find the link now) that one could not "restart" a backgroundWorker as I am trying to do.
The thread attemp is nearly identical but I thought I'd try in since there might be some constraints within the backgroundWorker that is not present in a regular thread. I thought.
namespace Devo
{
public partial class Form1 : Form
{
Thread PWC_counter_thread = new Thread(PWC_Counter);
private void fileSystemWatcher_Created(object sender, FileSystemEventArgs e)
{
if (PWC_counter_thread.IsAlive)
PWC_counter_thread.Abort();
//do a lot of stuff
PWC_counter_thread.Start();
}
static void PWC_Counter()
{
Thread.Sleep(180000);
DelayedMethod();
}
}
}
But this gave me the same error. On the second call to PWC_counter_thread.Start() is was busy.
I'm assuming that a race condition is not present as the second thread waits for, in this example, 3 minutes, and the initial FSW method takes a good full second to execute, therefore I believe that the call to .Abort() and .CancelAsync() both are done before their respective methods are completed.
Now for the questions:
Is it possible to restart a thread in the fashion I am trying? If so, what am I doing wrong?
Should I delay my method call in another way? If so, tips?
EDIT/UPDATE/SOLUTION
I never got starting and stopping a thread to work as I wanted so I found another solution to my situation.
The situation was that I had a second thread that worked as a sort of timer where it would call a method after a set amount of time. My first thread did some work and upon finishing it would start the second thread. If the first thread got fired up again before the timer-thread had finished it was supposed to kill the thread and restart it.
This proved, for me, to be difficult to get the way I wanted. So I instead took another approach towards my wanted end result. Instead of restarting the thread I simply restarted the stopwatch that my second thread was using as a counter. This gave me the result I wanted. It's probably bad practice but it works.
In your BackgroundWorker example you probably have an issue with racing. CancelAsync(), as its name implies, is an asynchronious call, meaning that BackgroundWorker does not stop working immediately and it might still work when try to restart it. To avoid that, you should subscribe to RunWorkerCompleted event and wait for it to fire before calling bw.RunWorkerAsync(); again. For example:
public Form1()
{
bw = new BackgroundWorker();
bw.RunWorkerCompleted += OnCompleted;
}
private BackgroundWorker bw;
private ManualResetEvent completed = new ManualResetEvent(false);
private void OnCompleted(object sender, RunWorkerCompletedEventArgs e)
{
completed.Set();
}
private void fileSystemWatcher_Created(object sender, FileSystemEventArgs e)
{
if (bw.IsBusy)
{
bw.CancelAsync();
completed.WaitOne();
}
//do a lot of stuff
completed.Reset();
bw.RunWorkerAsync();
}
You have multiple issues with your Thread-based example.
You should never call Thread.Abort(). Instead, you should implement a cancellation mechanism, similar to that of BackgroundWorker. Make a bool field (_isCancelled or something) and check it periodically in thread delegate.
You can not reuse a Thread object. You should always create a new one.
You would be best off encapsulating this in a class, and use a System.Threading.Timer to detect the inactivity.
Here's an example I put together. The idea is that you create an InactivityDetector with the appropriate inactivity threshold (an hour in your case) and a callback method that will be called when that period of inactivity is exceeded.
You have to call InactivityDetector.RegisterActivity() whenever activity is detected (e.g. in your case a file creation is detected).
Once the inactivity callback has been issued, it will not be called again until RegisterActivity() has been called again (this prevents multiple callbacks for the same period of extended inactivity).
Your code would pass DelayedMethod for the inactivity Action delegate.
Note that the callback is on a separate thread!
(Also note that I didn't put in any parameter validation, to keep the code shorter.)
using System;
using System.Threading;
namespace ConsoleApp1
{
sealed class Program
{
void test()
{
using (var inactivityDetector = new InactivityDetector(TimeSpan.FromSeconds(2), inactivityDetected))
{
for (int loop = 0; loop < 3; ++loop)
{
Console.WriteLine("Keeping busy once a second for 5 seconds.");
for (int i = 0; i < 5; ++i)
{
Thread.Sleep(1000);
Console.WriteLine("Registering activity");
inactivityDetector.RegisterActivity();
}
Console.WriteLine("Entering 3 second inactivity");
Thread.Sleep(3000);
inactivityDetector.RegisterActivity();
}
}
}
static void inactivityDetected()
{
Console.WriteLine("Inactivity detected.");
}
static void Main(string[] args)
{
new Program().test();
}
}
public sealed class InactivityDetector: IDisposable
{
public InactivityDetector(TimeSpan inactivityThreshold, Action onInactivity)
{
_inactivityThreshold = inactivityThreshold;
_onInactivity = onInactivity;
_timer = new Timer(timerCallback, null, (int)inactivityThreshold.TotalMilliseconds, -1);
}
public void RegisterActivity()
{
_timer.Change(-1, -1);
_timer.Change((int)_inactivityThreshold.TotalMilliseconds, -1);
}
private void timerCallback(object state)
{
_timer.Change(-1, -1);
_onInactivity();
}
public void Dispose()
{
_timer.Dispose();
}
private readonly TimeSpan _inactivityThreshold;
private readonly Action _onInactivity;
private readonly Timer _timer;
}
}

C#: Measure time taken and exit function when time elapsed

I would like to run a function (funcA) and use another function (timerFunc) as a timer. If the running function (funcA) has run for 10 seconds, I would like to exit it using the timer function (timerFunc). Is this possible? Basically what I am trying to do:
void funcA() {
// check event 1
// check event 2
// check event 3
// time reaches max here! --exit--
//check event 4
}
If not, what is the best way to handle such scenarios? I have considered using a stop-watch but I'm not sure if that is the best thing to do, mainly because I do not know after what event the timeout will be reached.
Thread t = new Thread(LongProcess);
t.Start();
if (t.Join(10 * 1000) == false)
{
t.Abort();
}
//You are here in at most 10 seconds
void LongProcess()
{
try
{
Console.WriteLine("Start");
Thread.Sleep(60 * 1000);
Console.WriteLine("End");
}
catch (ThreadAbortException)
{
Console.WriteLine("Aborted");
}
}
You could put all of the events into an array of Action or other type of delegate, then loop over the list and exit at the appropriate time.
Alternately, run all of the events in a background thread or Task or some other threading mechanism, and abort/exit the thread when you get to the appropriate time. A hard abort is a bad choice, as it can cause leaks, or deadlocks, but you could check CancellationToken or something else at appropriate times.
I would create a list and then very quickyl:
class Program
{
static private bool stop = false;
static void Main(string[] args)
{
Timer tim = new Timer(10000);
tim.Elapsed += new ElapsedEventHandler(tim_Elapsed);
tim.Start();
int eventIndex = 0;
foreach(Event ev in EventList)
{
//Check ev
// see if the bool was set to true
if (stop)
break;
}
}
static void tim_Elapsed(object sender, ElapsedEventArgs e)
{
stop = true;
}
}
This should work for a simple scenario. If it's more complex, we might need more details.

How can I synchronize these two threads?

here is the class:
public class Ticker
{
public event EventHandler Tick;
public EventArgs e = null;
public void TickIt()
{
while (true)
{
System.Threading.Thread.Sleep(300);
if (Tick != null)
{
Tick(this, e);
}
}
}
I'm running two threads in the windows form:
public partial class Form1 : Form
{
Ticker ticker1 = new Ticker();
Ticker ticker2 = new Ticker();
Thread t;
Thread t1;
public Form1()
{
InitializeComponent();
ticker1.Tick += ticker1_Tick;
ticker2.Tick += ticker2_Tick;
t = new Thread(new ThreadStart(ticker1.TickIt));
t1 = new Thread(new ThreadStart(ticker2.TickIt)));
t.Start();
t1.Start();
}
public void ticker1_Tick(object sender, EventArgs e)
{
if (this.InvokeRequired)
{
this.BeginInvoke((MethodInvoker)delegate
{
ticker1_Tick(sender, e);
});
return;
}
richTextBox1.Text += "t1 ";
}
public void ticker2_Tick(object sender, EventArgs e)
{
if (this.InvokeRequired)
{
this.BeginInvoke((MethodInvoker)delegate
{
ticker2_Tick(sender, e);
});
return;
}
richTextBox2.Text += "t2 ";
}
The problem is after some seconds thread t is ahead of t1 by several ticks.
First of all why is this happening, it doesn't make sense, since each thread should wait 300 ms before ticking?
Second, how can I sync these two threads, so they tick simultaneously and one doesn't get ahead of the other?
I can't put a lock before the while loop, then only one thread will be running, while the other is locked out. Putting a lock elsewhere doesn't change anything.
If you really need them to be perfectly in synch and execute the ticks in a certain order, you will need some kind of central timer as Jaime mentioned. If you need independent timing but want to prevent drift caused by Sleep being imprecise, or delay added by the time it takes to execute the event handler, something like this would work:
public class Ticker
{
public event EventHandler Tick;
public EventArgs e = null;
public void TickIt()
{
const int targetSleepTime = 300;
int nextTick = Environment.TickCount + targetSleepTime;
while (true)
{
System.Threading.Thread.Sleep(Math.Max(nextTick - Environment.TickCount, 0));
if (Tick != null)
{
Tick(this, e);
}
nextTick += targetSleepTime;
}
}
}
Just keep in mind Environment.TickCount can wrap back to Int32.MinValue when it gets to Int32.MaxValue. You'll need extra code to handle that, or maybe base the timing on DateTime.UtcNow (less overhead than DateTime.Now).
I don't think you can trust the sleep(300) to keep your threads running the same number of times independently...
One thing you could do is to have a central timer/tick generator that signals a synchronization object on each tick, and the thread function only ticks once and then WaitsForObject for the next tick to be generated from the main thread, effectively having one timer and telling the threads to tick synchronously.
Also note that the way you are subscribing to the thread function event, you need to consider race conditions in your handler functions. Each method will run on it's own thread (until the begininvoke) so, if you access any resource (class fields etc.) those would need to be synchronized. It's just too easy to forget what's going on with the threads. :(
How about using AutoResetEvent?
class Program
{
static readonly AutoResetEvent thread1Step = new AutoResetEvent(false);
static readonly AutoResetEvent thread2Step = new AutoResetEvent(false);
static void Main(string[] args)
{
new Thread(new ThreadStart(Thread1Main)).Start();
new Thread(new ThreadStart(Thread2Main)).Start();
}
private static void Thread1Main()
{
for (int i = 0; i < int.MaxValue; i++)
{
Console.WriteLine("thread1 i=" + i);
thread1Step.Set();
thread2Step.WaitOne();
}
}
private static void Thread2Main()
{
for (int i = 0; i < int.MaxValue; i++)
{
Console.WriteLine("thread2 i=" + i);
thread2Step.Set();
thread1Step.WaitOne();
}
}
}
Well you could use a Barrier if you're using .NET 4.0, but you would have to put it in your Ticker class otherwise you'll block your UI thread.
http://msdn.microsoft.com/en-us/library/system.threading.barrier.aspx
In your Ticker class, increase your polling frequency and check the system timer until you hit the interval you're looking for. You can use TickCount or Ticks if you can live with millisecond precision, or use StopWatch for higher precision if your system supports it.
To keep them synchronized, they'll need a common reference for a start-time. You can pass this in as a specific future tick to start syncing on or use something like Tick modulus 100. Or poll for a shared static flag that signifies when to start.
You cannot have absolute precision, so define what precision range you can live with from the outset, such as plus-or-minus 5ms between your Ticker threads.
One thing that'll help is to start a shared static StopWatch instance and echo its elapsed time in all of your logging to help you characterize any delays in your app.

C# event not being handled

I'm learning C# event handling by writing an app that uses the iTunes COM API. I have a method that should run when iTunes stops playing a song, but the method is never getting called when I trigger the event in the app by hitting the "stop/pause" button.
EDIT: Based on dboarman's reply, I deleted the while loop. Now the event does get handled, but only if I restart iTunes prior to running PlayPlaylist(). If I run PlayPlaylist() a second time, the stop event no longer gets fired/handled.
void trayIcon_Click(object sender, EventArgs e)
{
PlayPlaylist();
}
public static void PlayPlaylist()
{
itapp = new iTunesApp();
itapp.OnPlayerStopEvent +=
new _IiTunesEvents_OnPlayerStopEventEventHandler(itapp_OnPlayerStopEvent);
lastPlaylist = itapp.LibraryPlaylist;
itapp.Play();
}
static void itapp_OnPlayerStopEvent(object iTrack)
{
Debug.WriteLine("Stop Event fired");
//...
}
Updated source in Pastebin here (lines 59-68 are the relevant ones).
Spec: My app is supposed to play the songs in a Genius recommendations playlist from first to last (iTunes by default doesn't play Genius recommendations consecutively). The StopEvent should trigger the next song in the list to play.
Here is the complete code that is in question:
public static void PlayPlaylist()
{
itapp = new iTunesApp();
itapp.OnPlayerStopEvent += new _IiTunesEvents_OnPlayerStopEventEventHandler(itapp_OnPlayerStopEvent);
lastPlaylistID = itapp.LibraryPlaylist.playlistID;
Debug.WriteLine("Last playlist:");
Debug.WriteLine(lastPlaylistID);
itapp.Play();
while (true)
{
System.Threading.Thread.Sleep(1000);
}
}
I suspect that the while loop is causing the event to never fire because the thread will sleep for a second and because true is, well...always true.
I would put your playlist in into a list. Something like:
static List<myTrack> Tracks;
public static void PlayPlaylist()
{
itapp = new iTunesApp();
itapp.OnPlayerStopEvent += new _IiTunesEvents_OnPlayerStopEventEventHandler(itapp_OnPlayerStopEvent);
foreach (myTrack track in Tracks)
{
// perform play
}
}
See how that works for you.
When your itapp goes out of scope, be sure to release it with
System.Runtime.InteropServices.Marshal.ReleaseComObject(itapp);
or you'll have to restart iTunes for it to work again. Unregistering the event handlers with -= probably wouldn't hurt either.
If you want the thread to block and wait for the event you can use the ManualResetEvent class.
private ManualResetEvent _resetEvent;
public void PlayPlaylist()
{
_resetEvent = new ManualResetEvent(false);
itapp = new iTunesApp();
itapp.OnPlayerStopEvent += new _IiTunesEvents_OnPlayerStopEventEventHandler(itapp_OnPlayerStopEvent);
// Block until the resetEvent has been Set() or
// give up waiting after 5 minutes
_resetEvent.WaitOne(1000*5*60);
}
Inside itapp_OnPlayerStopEvent() you must call:
_resetEvent.Set();
To answer your original question, I'm pretty sure the while loop is not giving the thread any time to respond to the stop event, hence you are not seeing it being handled.
I'm wondering if the fact that the event handler doesn't unhook is causing an issue somewhere along the line (i.e. iTunes holds a singular reference to the initial instance of your app). This may solve it? I don't have the iTunes API so I'm flying a little blind; apologize if it's a waste of time.
private bool stopIt;
private void trayIcon_Click(object sender, EventArgs e)
{
if (!stopIt)
{
PlayPlaylist();
stopIt = true;
}
else
{
StopPlaylist();
stopIt = false;
}
}
public static void PlayPlaylist()
{
itapp = new iTunesApp();
itapp.OnPlayerStopEvent +=
new _IiTunesEvents_OnPlayerStopEventEventHandler(itapp_OnPlayerStopEvent);
lastPlaylist = itapp.LibraryPlaylist;
itapp.Play();
}
public static void StopPlaylist()
{
itapp.Stop(); // don't know if this is the right method name
// unhook the event so the reference object can free if necessary.
itapp.OnPlayerStopEvent -=
new _IiTunesEvents_OnPlayerStopEventEventHandler(itapp_OnPlayerStopEvent);
}
private static void itapp_OnPlayerStopEvent(object iTrack)
{
Debug.WriteLine("Stop Event fired");
// ...
}

Categories

Resources