Out of curiosity, is it possible to implement an interval at which the various events are raised when using the FileSystemWatcher?
Thanks!
There's an overload of FileSystemWatcher.WaitForChanged that take a timeout:
A synchronous method that returns a structure that contains specific information on the change that occurred, given the type of change you want to monitor and the time (in milliseconds) to wait before timing out.
So if your event doesn't happen before the timeout period you've set expires the event won't get fired.
I don't think there's a method/property that sets the minimum time between events.
Short answer - no. The class is event based. It does not have polling capabilities.
Short answer...maybe.
It depends on how this interval would be interpreted. If you want the FileSystemWatcher to raise one of its events periodically regardless of whether or not something actually changed then the answer is no.
But, if this interval is meant to control the minimum amount of time that has to elaspe prior to raising the next event then the asnwer is most definitely yes! The trick is to intercept the raising of the events and throttle them using a middle-man. Now this is only possible on a FileSystemWatcher (and a relatively small set of other event based classes) due to the fact that you can assign an ISynchronizeInvoke instance to the SynchronizingObject property. The synchronizing object would act as the middle-man and enforce the interval constraint.
Disclaimer: I am in no way advocating that anyone actually try this for various different reasons.
public void Main()
{
var watcher = new FileSystemWatcher();
watcher.SynchronizingObject = new Synchronizer(TimeSpan.FromSeconds(30));
}
public class Synchronizer : ISynchronizeInvoke
{
private TimeSpan m_Interval;
private Thread m_Thread;
private BlockingCollection<Message> m_Queue = new BlockingCollection<Message>();
public Synchronizer(TimeSpan interval)
{
m_Interval = interval;
m_Thread = new Thread(Run);
m_Thread.IsBackground = true;
m_Thread.Start();
}
private void Run()
{
DateTime last = DateTime.MinValue;
while (true)
{
Message message = m_Queue.Take();
DateTime received = DateTime.UtcNow;
TimeSpan span = DateTime.UtcNow - last;
TimeSpan wait = m_Interval - span;
if (wait > TimeSpan.Zero)
{
Thread.Sleep(wait);
}
message.Return = message.Method.DynamicInvoke(message.Args);
message.Finished.Set();
last = received;
}
}
public IAsyncResult BeginInvoke(Delegate method, object[] args)
{
Message message = new Message();
message.Method = method;
message.Args = args;
m_Queue.Add(message);
return message;
}
public object EndInvoke(IAsyncResult result)
{
Message message = result as Message;
if (message != null)
{
message.Finished.WaitOne();
return message.Return;
}
throw new ArgumentException("result");
}
public object Invoke(Delegate method, object[] args)
{
Message message = new Message();
message.Method = method;
message.Args = args;
m_Queue.Add(message);
message.Finished.WaitOne();
return message.Return;
}
public bool InvokeRequired
{
get { return Thread.CurrentThread != m_Thread; }
}
private class Message : IAsyncResult
{
public Delegate Method = null;
public object[] Args = null;
public object Return = null;
public object State = null;
public ManualResetEvent Finished = new ManualResetEvent(false);
public object AsyncState
{
get { return State; }
}
public WaitHandle AsyncWaitHandle
{
get { return Finished; }
}
public bool CompletedSynchronously
{
get { return false; }
}
public bool IsCompleted
{
get { return Finished.WaitOne(0); }
}
}
}
Related
I have a event in my code that can possibly get fired multiple times a second at some moment.
However I would like to implement a way to make that method wait 500ms before really firing, if the method gets called again before those 500ms are over, reset the timer and wait for 500ms again.
Coming from javascript I know this is possible with setTimeout or setInterval. However I'm having trouble figuring out how I could implement such a thing in C#.
You could use a System.Timers.Timer wrapped in a class to get the behaviour you need:
public class DelayedMethodCaller
{
int _delay;
Timer _timer = new Timer();
public DelayedMethodCaller(int delay)
{
_delay = delay;
}
public void CallMethod(Action action)
{
if (!_timer.Enabled)
{
_timer = new Timer(_delay)
{
AutoReset = false
};
_timer.Elapsed += (object sender, ElapsedEventArgs e) =>
{
action();
};
_timer.Start();
}
else
{
_timer.Stop();
_timer.Start();
}
}
}
This can then be used in the following manner:
public class Program
{
static void HelloWorld(int i)
{
Console.WriteLine("Hello World! " + i);
}
public static void Main(string[] args)
{
DelayedMethodCaller methodCaller = new DelayedMethodCaller(500);
methodCaller.CallMethod(() => HelloWorld(123));
methodCaller.CallMethod(() => HelloWorld(123));
while (true)
;
}
}
If you run the example, you will note that "Hello World! 123" is only displayed once - the second call simply resets the timer.
If you need to reset the timer when the method is called again, consider looking at the ManualResetEvent class:
https://msdn.microsoft.com/en-us/library/system.threading.manualresetevent(v=vs.110).aspx
You can use this to notify one or more waiting threads that an event has occurred.
You can use Thread.Sleep() with locking
private object locking = new object();
lock (locking )
{
Thread.Sleep(500);
//Your code to run here
}
https://msdn.microsoft.com/en-us/library/system.threading.thread.sleep(v=vs.110).aspx
Just writen super simple class with System.Threading.Thread; With a little different approach Usage.
var delayedCaller = new DelayedTimeout(() => HelloWorld(123), 500, false);
delayedCaller.ResetTimer();
delayedCaller.ResetTimer();
Currently, you can do it very simple with the following class
public class DelayedTimeout
{
readonly Timer _timer;
readonly int _timeoutMs;
public DelayedTimeout(TimerCallback callback, int timeoutMs, bool startNow)
{
_timeoutMs = timeoutMs;
// Should we start now
var currentTimeoutMs = startNow ? _timeoutMs : Timeout.Infinite;
_timer = new Timer(callback, null, currentTimeoutMs, Timeout.Infinite);
}
// Constructor overloading
public DelayedTimeout(Action callback, int timeoutMs, bool startNow) :
this(delegate (object? obj) { callback.Invoke(); }, timeoutMs, startNow)
{}
public void ResetTimer()
{
_timer.Change(Timeout.Infinite, Timeout.Infinite); // Stop the timer
_timer.Change(_timeoutMs, Timeout.Infinite); // Stop the timer
}
}
I tell the Timer to start in the constructor. It starts, but when it reaches its Timer.Elapsed event it only runs the first if statement in the method. I've checked to see if isWatching is true, and it is, but it still skips it entirely. It doesn't even reach the if(isWatching) line.
Code:
MainWindow.xaml.cs:
public partial class MainWindow : Window
{
public SessionManager SM { get; private set; }
public MainWindow()
{
SM = new SessionManager();
SM.NewDayEvent += SplitSession;
///code
}
}
SessionManager.cs (Some variables have been omitted from this post):
public class SessionManager : INotifyPropertyChanged
{
public delegate void NewDayEventHandler(object sender, EventArgs ea);
public event NewDayEventHandler NewDayEvent;
private bool _isWatching;
private Timer _timer;
private bool isWatching
{
get
{
return _isWatching;
}
set
{
_isWatching = value;
if (!_isWatching)
{
_clockWatch.Stop();
}
else
{
_clockWatch.Start();
}
}
}
#endregion
public SessionManager()
{
_clockWatch = new Stopwatch();
_timer = new Timer(1000);
_timer.Elapsed += timerElapsed;//focus on this here
_isWatching = false;
current_time = new DateTime();
CurrentTime = DateTime.Now;
_timer.Start();
}
public void timerElapsed(object sender, ElapsedEventArgs e)
{
CurrentTime = DateTime.Now;
if (CurrentTime.TimeOfDay == TimeSpan.Parse("9:32 AM") && NewDayEvent != null)
{
NewDayEvent(this, new EventArgs());
}
if (isWatching)
{
if (CurrentSession != null)
{
//update the timespent variable of the current timeEntry
if (CurrentSession.currentTimeEntry != null)
{
CurrentSession.currentTimeEntry.TimeSpent = _clockWatch.Elapsed;
calculateTotalTime();
CalculateFilteredTimeSpent();
}
}
}
}
}
You aren't using the correct format while calling TimeSpan.Parse(). The right way to do what you are trying to is:
TimeSpan.Parse("9:32")
Your current code snippet throws a System.FormatException:
A first chance exception of type 'System.FormatException' occurred in mscorlib.dll
However for what you are trying to achieve, trigger an action once every day at a particular time, the above method might not be the best since the chances of it succeeding are very less. The timer will run every 1000 ms and then return the current time of day which has milliseconds included. So the timer elapsed event could be called at 9:32.0001 and might never pass the condition. A better alternative is probably:
if (CurrentTime.TimeOfDay >= TimeSpan.Parse("9:32") && NewDayEvent != null)
This will trigger more than once after that time has elapsed, so you could add a flag which keeps track of what day the last event was processed.
Alternatively you could also look at ScheduleAction in .NET 4.5 or some of the solutions here.
There is this class unit that has a property bool status that marks whether a method, request, should be called on the unit. I have my other class, and in it, there is a method that should call request. To avoid blocking the main thread, I want to call the method asynchronously. The problem is that there isn't an event for the status change, and I don't want to make my asynchronous call do ugly stuff like:
while(!status){}unit.request(args);
or
while(!status){Thread.Sleep(100)}unit.request(args);
especially when I do not know the timescale in which status turns true.
How do I do this?
update: i forgot to mention that i cannot change unit. sorry for that.
You want to call a function (be it asynchronously or not) when a property changes. You have two choices:
Attach to an even that is signalled when the property changes
Periodically check the value of the property
You can't do the first, so you must do the second.
This is a sample of how you can manage this using an event.
Suppose this is your class
public class Unit
{
private readonly object _syncRoot = new object();
private bool _status;
public event EventHandler OnChanged;
public bool Status
{
get
{
lock (_syncRoot)
{
return _status;
}
}
set
{
lock (_syncRoot)
{
_status = value;
if (_status && OnChanged != null)
{
OnChanged.Invoke(this, null);
}
}
}
}
public void Process()
{
Thread.Sleep(1000);
Status = true;
}
}
Here is how you can use it
class Program
{
static void Main(string[] args)
{
var unit = new Unit();
unit.OnChanged += Unit_OnChanged;
Console.WriteLine("Before");
Task.Factory.StartNew(unit.Process);
Console.WriteLine("After");
Console.WriteLine("Manual blocking, or else app dies");
Console.ReadLine();
}
static void Unit_OnChanged(object sender, EventArgs e)
{
//Do your processing here
Console.WriteLine("Unit_OnChanged before");
Task.Factory.StartNew(()=>
{
Thread.Sleep(1000);
Console.WriteLine("Unit_OnChanged finished");
});
Console.WriteLine("Unit_OnChanged after");
}
}
This outputs
Before
After
Manual blocking, or else app dies
Unit_OnChanged before
Unit_OnChanged after
Unit_OnChanged finished
This is the classic polling problem, and there really isn't an elegant solution when polling is concerned. But we can work some functional programming in to get something which isn't a nightmare to use.
public static CancellationTokenSource Poll(
Func<bool> termination,
Action<CancellationToken> onexit,
int waitTime = 0,
int pollInterval = 1000)
{
var cts = new CancellationTokenSource();
var token = cts.Token;
Action dispose = cts.Cancel;
var timer = new Timer(_ =>
{
if (termination() || token.IsCancellationRequested)
{
onexit(token);
dispose();
}
}, null, waitTime, pollInterval);
dispose = timer.Dispose;
return cts;
}
Example:
var condition = false;
Poll(() => condition == true, ct => Console.WriteLine("Done!"));
Console.ReadLine();
condition = true;
Console.ReadLine();
Use a System.Threading.AutoResetEvent instead of a bool if possible:
AutoResetEvent status = new AutoResetEvent();
In your asynchronous method, wait for it:
status.WaitOne();
unit.request(args);
Then, to signal it in your other class, call Set:
status.Set();
Many areas in a project I'm working on have a simple timeout check which basically runs code through a try loop until it succeeds or 10 seconds elapses.
class Timeout {
private readonly DateTime timeoutDate;
public bool FlagSuccess;
public Timeout() {
timeoutDate = DateTime.UtcNow.AddSeconds(10);
flagSuccess = false;
}
public bool continueRunning() {
if (!flagSuccess && DateTime.UtcNow < timeoutDate) return true;
else return false;
}
}
Here is an example of the class in use:
Timeout t = new Timeout();
while (t.continueRunning()) {
try {
//PUT CODE HERE
t.flagSuccess = true;
}
catch(Exception e) {
Console.WriteLine(e.Message);
}
}
Before I implement this, is there a better and more standard way to do this? What I have above is based on my blind intuition.
Use .NETs Timer class(es):
using System.Timers;
public static void Main() {
Timer t = new Timer();
t.Elapsed += new ElapsedEventHandler(ActionWhenFinished);
t.Interval = 10000;
t.Start();
}
public static void ActionWhenFinished()
{
// cancel any action
}
Your Timeout class will block the current thread it is running in, which isn't the case with System.Timer.
I'd suggest changing your loop to a do-while loop, so that you're guaranteed to run the loop at least once even if your thread gets momentarily waylaid between setting up the timeout and starting the loop. Also, I'd suggest that it may be helpful to have the Timeout class include a RemainingMilliseconds property, and maybe RemainingMillisecondsUpTo(Integer N) function, which could be passed to various block-or-timeout routines.
Looks kind of like a busy loop to me, but here's how you'd do it with a StopWatch.
System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch();
timer.Start();
bool complete;
while( timer.ElapsedMilliseconds < 10000 && !complete)
{
//Do stuff
// and someday... complete = true;
}
You could wrap that up into a simple class as well if you like.
class AgingWait
{
System.Diagnostics.Stopwatch _watch = new System.Diagnostics.Stopwatch();
int maxMilliseconds;
bool forceExpire;
public bool Expired
{
get { return forceExpire || maxMilliseconds < _watch.ElapsedMilliseconds; }
}
public AgingWait(int milli)
{
_watch.Start();
maxMilliseconds = milli;
}
public void Expire()
{
forceExpire = true;
}
}
to use
AgingWait waiter = new AgingWait(1000);
while (!waiter.Expired)
{
if (condition)
waiter.Expire();
}
I have a Sender class that sends a Message on a IChannel:
public class MessageEventArgs : EventArgs {
public Message Message { get; private set; }
public MessageEventArgs(Message m) { Message = m; }
}
public interface IChannel {
public event EventHandler<MessageEventArgs> MessageReceived;
void Send(Message m);
}
public class Sender {
public const int MaxWaitInMs = 5000;
private IChannel _c = ...;
public Message Send(Message m) {
_c.Send(m);
// wait for MaxWaitInMs to get an event from _c.MessageReceived
// return the message or null if no message was received in response
}
}
When we send messages, the IChannel sometimes gives a response depending on what kind of Message was sent by raising the MessageReceived event. The event arguments contain the message of interest.
I want Sender.Send() method to wait for a short time to see if this event is raised. If so, I'll return its MessageEventArgs.Message property. If not, I return a null Message.
How can I wait in this way? I'd prefer not to have do the threading legwork with ManualResetEvents and such, so sticking to regular events would be optimal for me.
Use a AutoResetEvent.
Gimme a few minutes and I'll throw together a sample.
Here it is:
public class Sender
{
public static readonly TimeSpan MaxWait = TimeSpan.FromMilliseconds(5000);
private IChannel _c;
private AutoResetEvent _messageReceived;
public Sender()
{
// initialize _c
this._messageReceived = new AutoResetEvent(false);
this._c.MessageReceived += this.MessageReceived;
}
public Message Send(Message m)
{
this._c.Send(m);
// wait for MaxWaitInMs to get an event from _c.MessageReceived
// return the message or null if no message was received in response
// This will wait for up to 5000 ms, then throw an exception.
this._messageReceived.WaitOne(MaxWait);
return null;
}
public void MessageReceived(object sender, MessageEventArgs e)
{
//Do whatever you need to do with the message
this._messageReceived.Set();
}
}
Have you tried assigning the function to call asynchronously to a delegate, then invoking the mydelegateinstance.BeginInvoke?
Linky for reference.
With the below example, just call
FillDataSet(ref table, ref dataset);
and it'll work as if by magic. :)
#region DataSet manipulation
///<summary>Fills a the distance table of a dataset</summary>
private void FillDataSet(ref DistanceDataTableAdapter taD, ref MyDataSet ds) {
using (var myMRE = new ManualResetEventSlim(false)) {
ds.EnforceConstraints = false;
ds.Distance.BeginLoadData();
Func<DistanceDataTable, int> distanceFill = taD.Fill;
distanceFill.BeginInvoke(ds.Distance, FillCallback<DistanceDataTable>, new object[] { distanceFill, myMRE });
WaitHandle.WaitAll(new []{ myMRE.WaitHandle });
ds.Distance.EndLoadData();
ds.EnforceConstraints = true;
}
}
/// <summary>
/// Callback used when filling a table asynchronously.
/// </summary>
/// <param name="result">Represents the status of the asynchronous operation.</param>
private void FillCallback<MyDataTable>(IAsyncResult result) where MyDataTable: DataTable {
var state = result.AsyncState as object[];
Debug.Assert((state != null) && (state.Length == 2), "State variable is either null or an invalid number of parameters were passed.");
var fillFunc = state[0] as Func<MyDataTable, int>;
var mre = state[1] as ManualResetEventSlim;
Debug.Assert((mre != null) && (fillFunc != null));
int rowsAffected = fillFunc.EndInvoke(result);
Debug.WriteLine(" Rows: " + rowsAffected.ToString());
mre.Set();
}
Perhaps your MessageReceived method should simply flag a value to a property of your IChannel interface, while implementing the INotifyPropertyChanged event handler, so that you would be advised when the property is changed.
By doing so, your Sender class could loop until the max waiting time is elapsed, or whenever the PropertyChanged event handler occurs, breaking the loop succesfully. If your loop doesn't get broken, then the message shall be considered as never received.
Useful sample with AutoResetEvent:
using System;
using System.Threading;
class WaitOne
{
static AutoResetEvent autoEvent = new AutoResetEvent(false);
static void Main()
{
Console.WriteLine("Main starting.");
ThreadPool.QueueUserWorkItem(
new WaitCallback(WorkMethod), autoEvent);
// Wait for work method to signal.
autoEvent.WaitOne();
Console.WriteLine("Work method signaled.\nMain ending.");
}
static void WorkMethod(object stateInfo)
{
Console.WriteLine("Work starting.");
// Simulate time spent working.
Thread.Sleep(new Random().Next(100, 2000));
// Signal that work is finished.
Console.WriteLine("Work ending.");
((AutoResetEvent)stateInfo).Set();
}
}
WaitOne is really the right tool for this job. In short, you want to wait between 0 and MaxWaitInMs milliseconds for a job to complete. You really have two choices, poll for completion or synchronize the threads with some construct that can wait an arbitrary amount of time.
Since you're well aware of the right way to do this, for posterity I'll post the polling version:
MessageEventArgs msgArgs = null;
var callback = (object o, MessageEventArgs args) => {
msgArgs = args;
};
_c.MessageReceived += callback;
_c.Send(m);
int msLeft = MaxWaitInMs;
while (msgArgs == null || msLeft >= 0) {
Thread.Sleep(100);
msLeft -= 100; // you should measure this instead with say, Stopwatch
}
_c.MessageRecieved -= callback;