.NET Throw exception / raise event after X number of seconds - c#

In a long running C# method I want to throw an exception or raise an event after a number of seconds have elapsed.
Is this possible?

You can do this by using a timer - set it for the timeout you wish and start it at the start of the method.
At the very end of the method, disable the timer - it will only fire if it times out and you can hook up to the tick event.
var timer = new Timer(timeout);
timer.Elapsed = ElapsedEventHanler; // Name of the event handler
timer.Start();
// do long running process
timer.Stop();
I suggest reading up on the different timer classes - this will let you know which of them is best suited for your particular needs.

Use System.Threading.Timer:
System.Threading.Timer t;
int seconds = 0;
public void start() {
TimerCallback tcb = new TimerCallback(tick);
t = new System.Threading.Timer(tcb);
t.Change(0, 1000);
}
public void tick(object o)
{
seconds++;
if (seconds == 60)
{
// do something
}
}

If you intend to stop a long running method then I think adding Cancellation support to the method would be a better approach instead of raising the exception.

Try the following, which has functionality for cancelling the exception (if the process completed) and raises the exception on the source thread:
var targetThreadDispatcher = Dispatcher.CurrentDispatcher;
var tokenSource = new CancellationTokenSource();
var cancellationToken = tokenSource.Token;
Task.Factory.StartNew(() =>
{
var ct = cancellationToken;
// How long the process has to run
Task.Delay(TimeSpan.FromSeconds(5));
// Exit the thread if the process completed
ct.ThrowIfCancellationRequest();
// Throw exception to target thread
targetThreadDispatcher.Invoke(() =>
{
throw new MyExceptionClass();
}
}, cancellationToken);
RunProcess();
// Cancel the exception raising if the process was completed.
tokenSource.Cancel();

Related

C# event exception not caught in parent method

I`m working on implementing a get method for cache. This method will return to caller if a maximum wait time has passed(in my case 100ms for tests).
My issue is that the exception NEVER reaches the catch, after the timer triggered the event.
Please help me understand why? (I read that events are executed on the same thread, so that should`t be the issue)
public static T Get<T>(string key, int? maxMilisecondsForResponse = null)
{
var result = default(T);
try
{
// Return default if time expired
if (maxMilisecondsForResponse.HasValue)
{
var timer = new System.Timers.Timer(maxMilisecondsForResponse.Value);
timer.Elapsed += OnTimerElapsed;
timer.AutoReset = false;
timer.Enabled = true; // start the timer
}
var externalCache = new CacheServiceClient(BindingName);
Thread.Sleep(3000); // just for testing
}
catch (Exception ex)
{
// why is the exception not caught here?
}
return result;
}
private static void OnTimerElapsed(object source, System.Timers.ElapsedEventArgs e)
{
throw new Exception("Timer elapsed");
}
The timer fires on it's own thread. You can read more about it in this answer.
The answer to your question is to use async methods that can be cancelled. Then you can use a cancellation token source and do it the proper way instead of homebrewing a solution with timers.
You can find a good overview here.
For example:
cts = new CancellationTokenSource();
cts.CancelAfter(2500);
await Task.Delay(10000, cts.Token);
This would cancel the waiting task after 2500 (of 10000) because it took too long. Obviously you need to insert your own logic in a task instead of just waiting.
From MSDN
The Timer component catches and suppresses all exceptions thrown by
event handlers for the Elapsed event. This behavior is subject to
change in future releases of the .NET Framework.
And continues
Note, however, that this is not true of event handlers that execute
asynchronously and include the await operator (in C#) or the Await
operator (in Visual Basic). Exceptions thrown in these event handlers
are propagated back to the calling thread.
Please take a look Exception Handling (Task Parallel Library)
An applied example below:
public class Program
{
static void Main()
{
Console.WriteLine("Begin");
Get<string>("key", 1000);
Console.WriteLine("End");
}
public static T Get<T>(string key, int? maxMilisecondsForResponse = null)
{
var result = default(T);
try
{
var task = Task.Run(async () =>
{
await Task.Delay(maxMilisecondsForResponse.Value);
throw new Exception("Timer elapsed");
});
task.Wait();
}
catch (Exception ex)
{
// why the exception is not catched here?
Console.WriteLine(ex);
}
return result;
}
}
The timer is being executed in the own thread but you can't catch the exception at the caller level. So, it is not a good approach to use timer in this case and you can change it by creating the Task operation.
var result = default(T);
CacheServiceClient externalCache;
if (!Task.Run(() =>
{
externalCache = new CacheServiceClient(BindingName);
return externalCache;
}).Wait(100))//Wait for the 100 ms to complete operation.
{
throw new Exception("Task is not completed !");
}
// Do something
return result;

Set property value when all threads are finished?

In my application there are three threads like:
private Thread _analysisThread;
private Thread _head2HeadThread;
private Thread _formThread;
and each thread is started in the following way:
if (_analysisThread == null || !_analysisThread.IsAlive)
{
_analysisThread = new Thread(() => { Analysis.Logic(match); });
_analysisThread.Start();
}
I've a ListView where the user can select an item and then start again the thread, but I want prevent this 'cause the methods inside each thread are heavy, so need time to complete them.
Until now I want disable the ListView selection, so I did:
<ListView IsEnabled="{Binding IsMatchListEnabled}">
private bool _isMatchListEnabled = true;
public bool IsMatchListEnabled
{
get { return _isMatchListEnabled; }
set
{
_isMatchListEnabled = value;
OnPropertyChanged();
}
}
before a new Thread start I do: IsMatchListEnabled = false; but what I need to do is check if all thread are finished and then do: IsMatchListEnabled = true;, actually if I enable the ListView after all thread, I get the ListView even enabled 'cause the Thread code is async, and the code outside the Thread is sync, so actually this property is useless.
What I tried to avoid this is create an infinite loop like this:
while (true)
{
if (!_analysisThread.IsAlive && !_head2HeadThread.IsAlive && !_formThread.IsAlive)
{
IsMatchListEnabled = true;
break;
}
}
this loop is placed after all threads execution, but as you can imagine, this will freeze the application.
Any solution?
All comments are correct — it's better to use Tasks. Just to answer OP's question.
You can synchronize threads with ManualResetEvent, having an array of events by the number of threads and one additional thread to change IsMatchListEnabled when all threads are finished.
public static void SomeThreadAction(object id)
{
var ev = new ManualResetEvent(false);
events[id] = ev; // store the event somewhere
Thread.Sleep(2000 * (int)id); // do your work
ev.Set(); // set the event signaled
}
Then, somewhere else we need to initialize waiting routine.
// we need tokens to be able to cancel waiting
var cts = new CancellationTokenSource();
var ct = cts.Token;
Task.Factory.StartNew(() =>
{
bool completed = false;
while (!ct.IsCancellationRequested && !completed)
{
// will check if our routine is cancelled each second
completed =
WaitHandle.WaitAll(
events.Values.Cast<ManualResetEvent>().ToArray(),
TimeSpan.FromSeconds(1));
}
if (completed) // if not completed, then somebody cancelled our routine
; // change your variable here
});
Complete example can be found and viewed here.
I would suggest using Microsoft's Reactive Framework for this. It's more powerful than tasks and the code is far simpler than using threads.
Let's say you have 3 long-running operations:
Action huey = () => { Console.WriteLine("Huey Start"); Thread.Sleep(5000); Console.WriteLine("Huey Done"); };
Action dewey = () => { Console.WriteLine("Dewey Start"); Thread.Sleep(5000); Console.WriteLine("Dewey Done"); };
Action louie = () => { Console.WriteLine("Louie Start"); Thread.Sleep(5000); Console.WriteLine("Louie Done"); };
Now you can write the following simple query:
IObservable<Unit> query =
from a in new [] { huey, dewey, louie }.ToObservable()
from u in Observable.Start(() => a())
select u;
You run it like this:
Stopwatch sw = Stopwatch.StartNew();
IDisposable subscription = query.Subscribe(u => { }, () =>
{
Console.WriteLine("All Done in {0} seconds.", sw.Elapsed.TotalSeconds);
});
The results I get are:
Huey Start
Dewey Start
Louie Start
Huey Done
Louie Done
Dewey Done
All Done in 5.0259197 seconds.
Three 5 second operations complete in 5.03 seconds. All in parallel.
If you want to stop the computation early just call subscription.Dispose().
NuGet "System.Reactive" to get the bits.

Monitoring a synchronous method for timeout

I'm looking for an efficient way to throw a timeout exception if a synchronous method takes too long to execute. I've seen some samples but nothing that quite does what I want.
What I need to do is
Check that the sync method does exceed its SLA
If it does throw a timeout exception
I do not have to terminate the sync method if it executes for too long. (Multiple failures will trip a circuit breaker and prevent cascading failure)
My solution so far is show below. Note that I do pass a CancellationToken to the sync method in the hope that it will honor a cancellation request on timeout. Also my solution returns a task that can then be awaited on etc as desired by my calling code.
My concern is that this code creates two tasks per method being monitoring. I think the TPL will manage this well, but I would like to confirm.
Does this make sense? Is there a better way to do this?
private Task TimeoutSyncMethod( Action<CancellationToken> syncAction, TimeSpan timeout )
{
var cts = new CancellationTokenSource();
var outer = Task.Run( () =>
{
try
{
//Start the synchronous method - passing it a cancellation token
var inner = Task.Run( () => syncAction( cts.Token ), cts.Token );
if( !inner.Wait( timeout ) )
{
//Try give the sync method a chance to abort grecefully
cts.Cancel();
//There was a timeout regardless of what the sync method does - so throw
throw new TimeoutException( "Timeout waiting for method after " + timeout );
}
}
finally
{
cts.Dispose();
}
}, cts.Token );
return outer;
}
Edit:
Using #Timothy's answer I'm now using this. While not significantly less code it is a lot clearer. Thanks!
private Task TimeoutSyncMethod( Action<CancellationToken> syncAction, TimeSpan timeout )
{
var cts = new CancellationTokenSource();
var inner = Task.Run( () => syncAction( cts.Token ), cts.Token );
var delay = Task.Delay( timeout, cts.Token );
var timeoutTask = Task.WhenAny( inner, delay ).ContinueWith( t =>
{
try
{
if( !inner.IsCompleted )
{
cts.Cancel();
throw new TimeoutException( "Timeout waiting for method after " + timeout );
}
}
finally
{
cts.Dispose();
}
}, cts.Token );
return timeoutTask;
}
If you have a Task called task, you can do this:
var delay = Task.Delay(TimeSpan.FromSeconds(3));
var timeoutTask = Task.WhenAny(task, delay);
If timeoutTask.Result ends up being task, then it didn't timeout. Otherwise, it's delay and it did timeout.
I don't know if this is going to behave identically to what you have implemented, but it's the built-in way to do this.
I have re-written this solution for .NET 4.0 where some methods are not available e.g.Delay. This version is monitoring a method which returns object. How to implement Delay in .NET 4.0 comes from here: How to put a task to sleep (or delay) in C# 4.0?
public class OperationWithTimeout
{
public Task<object> Execute(Func<CancellationToken, object> operation, TimeSpan timeout)
{
var cancellationToken = new CancellationTokenSource();
// Two tasks are created.
// One which starts the requested operation and second which starts Timer.
// Timer is set to AutoReset = false so it runs only once after given 'delayTime'.
// When this 'delayTime' has elapsed then TaskCompletionSource.TrySetResult() method is executed.
// This method attempts to transition the 'delayTask' into the RanToCompletion state.
Task<object> operationTask = Task<object>.Factory.StartNew(() => operation(cancellationToken.Token), cancellationToken.Token);
Task delayTask = Delay(timeout.TotalMilliseconds);
// Then WaitAny() waits for any of the provided task objects to complete execution.
Task[] tasks = new Task[]{operationTask, delayTask};
Task.WaitAny(tasks);
try
{
if (!operationTask.IsCompleted)
{
// If operation task didn't finish within given timeout call Cancel() on token and throw 'TimeoutException' exception.
// If Cancel() was called then in the operation itself the property 'IsCancellationRequested' will be equal to 'true'.
cancellationToken.Cancel();
throw new TimeoutException("Timeout waiting for method after " + timeout + ". Method was to slow :-)");
}
}
finally
{
cancellationToken.Dispose();
}
return operationTask;
}
public static Task Delay(double delayTime)
{
var completionSource = new TaskCompletionSource<bool>();
Timer timer = new Timer();
timer.Elapsed += (obj, args) => completionSource.TrySetResult(true);
timer.Interval = delayTime;
timer.AutoReset = false;
timer.Start();
return completionSource.Task;
}
}
How to use it then in Console app.
public static void Main(string[] args)
{
var operationWithTimeout = new OperationWithTimeout();
TimeSpan timeout = TimeSpan.FromMilliseconds(10000);
Func<CancellationToken, object> operation = token =>
{
Thread.Sleep(9000); // 12000
if (token.IsCancellationRequested)
{
Console.Write("Operation was cancelled.");
return null;
}
return 123456;
};
try
{
var t = operationWithTimeout.Execute(operation, timeout);
var result = t.Result;
Console.WriteLine("Operation returned '" + result + "'");
}
catch (TimeoutException tex)
{
Console.WriteLine(tex.Message);
}
Console.WriteLine("Press enter to exit");
Console.ReadLine();
}
To elabolate on Timothy Shields clean solution:
if (task == await Task.WhenAny(task, Task.Delay(TimeSpan.FromSeconds(3))))
{
return await task;
}
else
throw new TimeoutException();
This solution, I found, will also handle the case where the Task has a return value - i.e:
async Task<T>
More to be found here: MSDN: Crafting a Task.TimeoutAfter Method
Jasper's answer got me most of the way, but I specifically wanted a void function to call a non-task synchronous method with a timeout. Here's what I ended up with:
public static void RunWithTimeout(Action action, TimeSpan timeout)
{
var task = Task.Run(action);
try
{
var success = task.Wait(timeout);
if (!success)
{
throw new TimeoutException();
}
}
catch (AggregateException ex)
{
throw ex.InnerException;
}
}
Call it like:
RunWithTimeout(() => File.Copy(..), TimeSpan.FromSeconds(3));

C# Background Worker RunWorkerCompleted Never Fires - Why?

Update
I'm now wondering if the fact that the IEnumerable that the foreach loop iterates over here is from a loop that uses yield return. I'm not sure if this has any effect on threading... ?
Can anyone point out why I never see the BackgroundWorker RunWorkerCompleted event fire in this code (this is a .NET 4, MVC 3 application)?
Regardless of what I set for, WorkerSupportsCancellation and WorkerReportsProgress the completed events never seem to fire.
Even when I try throwing an exception in the DoWork block, I never see the completed event. As I understand it, I should.
Anything obvious here?
By the way, I'm unable to upgrade the project to .NET 4.5 to use newer async features due to project restrictions.
var autoResetEvent = new AutoResetEvent(false);
UploadsExpected = pagesFound;
foreach (var rasterisedPageFilePath in rasterisedPageFilePathList)
{
// Track uploads
UploadsStarted += 1;
int uploadCount = UploadsStarted;
// Track concurrent uploads in main thread and while we are at our
// maximum, pause and wait before starting the next upload thread
while (ConcurrentUploadsRunning >= maxConcurrentUploads)
{
Debug.WriteLine(string.Format("Waiting to start upload: {0}",
uploadCount));
Thread.Sleep(3000);
}
ConcurrentUploadsRunning += 1;
Debug.WriteLine(string.Format("Initiating new upload: {0}", uploadCount));
// Create a background worker so we can run the upload asynchronously.
var backgroundWorker = new BackgroundWorker();
// Set up anonymous method that runs asynchronously
backgroundWorker.DoWork += (sender, e) =>
{
try
{
var storageManager = new storageManager(awsS3BucketName);
string imgFilePath = (string) e.Argument;
using (var fileStream = new FileStream(imgFilePath, FileMode.Open))
{
storageManager.Save(Path.GetFileName(imgFilePath),
MimeTypes.JPEG, fileStream);
}
}
catch (Exception ex)
{
UploadHasFailed = true;
m_logManager.Fatal("Upload of file to AWS S3 has failed", ex);
}
// Run check for AutoResetEvent following Save complete,
// and if the completed uploads count indicates that all uploads
// have finished, set AutoResetEvent so main thread can exit
if ((UploadsCompleted += 1) == UploadsExpected)
{
autoResetEvent.Set();
}
Debug.WriteLine(string.Format("Upload complete: {0}", uploadCount));
ConcurrentUploadsRunning -= 1;
};
backgroundWorker.RunWorkerCompleted += (sender, args) =>
{
// Never fires
};
backgroundWorker.ProgressChanged += (sender, args) =>
{
// Never fires
};
backgroundWorker.RunWorkerAsync(rasterisedPageFilePath);
}
autoResetEvent.WaitOne();
try
{
inputStream.Close();
} catch { }
There are many strange quirks in this code - is the thread executing the code above your main thread or some other thread? Either way, if it's your GUI thread then it's blocking (.Sleep(3000)), if it isn't, then you create your backgroundworker in the wrong context

Running task in loop

I have a function which can take 5-60 seconds to run, and I need to run it for every 10 seconds but it should be started only when the previously started function finished running, my code for now is
Action myAction = new Action(() =>
{
Debug.WriteLine("just testing");
Thread.Sleep(15000);
});
Task myTask = Task.Factory.StartNew(myAction, _cts.Token);
Timer myTimer = new Timer(state =>
{
if (myTask.IsCompleted)
{
myTask = Task.Factory.StartNew(myAction, _cts.Token);
}
}, null, 10000, 10000);
Everything is working fine but I wonder if there is a better solution for my problem? Or is there a possibility to not create a new task (Task.Factory.StartNew) but just using the one used by myTimer?
You can use ContinueWith():
Task.Factory.StartNew(myAction, _cts.Token).ContinueWith(_ => myAction);
Look for it's overloads, it has many options to control on which cases to run the continuation.
There is a great open source task scheduler called Quartz.net. You can find it at http://quartznet.sourceforge.net/
It supports the specific scenario you mentioned. It is a very robust solution with good extensibility.
Another possibility, if you are adventurous, would be to use Rx:
Observable.Timer(TimeSpan.FromSeconds(10)).TakeUntilCanceled(cancel).Subscribe(_ => myAction);
Using the TakeUntilCanceled extension:
public static class CancellationTokenXs
{
public static IObservable<T>
TakeUntilCanceled<T>(this IObservable<T> source, CancellationToken cancellationToken)
{
var subject = new Subject<Unit>();
cancellationToken.Register(() => subject.OnNext(new Unit()), true);
return source.TakeUntil(subject);
}
}
A much better idea would be to, instead of trying to call it every 10 seconds, rely on a callback on task completion, as an example in the following code:
DateTime sinceExec = DateTime.Now;
BackgroundWorker bgWorker = new BackgroundWorker();
bgWorker.DoWork += (bgSender, bgArgs) =>
{
sinceExec = DateTime.Now;
Debug.WriteLine("Test!");
Thread.Sleep(5000);
};
bgWorker.RunWorkerCompleted += (bgSender, bgArgs) =>
{
// it didn't take 10000 milliseconds
if ((DateTime.Now - sinceExec).Milliseconds < 10000)
{
//Calculate time to wait
TimeSpan timeToWait = (DateTime.Now - sinceExec);
// wait that amount of time
Thread.Sleep(timeToWait);
}
//Re-execute the worker
bgWorker.RunWorkerAsync();
};
bgWorker.RunWorkerAsync();
The BackgroundWorker class functions such that the event handler DoWork is executed when RunWorkerAsync() is called and RunWorkerCompleted is invoked when DoWork completes.
You can use a lock statement. A lock statement creates a critical section, only one of which can be run at once for a given object.
Use an object both your main thread and your task thread can have access to as the mutex lock. Surrounding both the task function's code and the line that starts the task with the lock statement will accomplish your goal. The task function will acquire the lock and will not release it until it has finished, and the creation function will wait to acquire the lock before it creates another task.
Action myAction = new Action(() =>
{
lock(this)
{
Debug.WriteLine("just testing");
Thread.Sleep(15000);
}
});
And in your code that kicks off the action,
lock(myAction)
{
Task.Factory.StartNew(myAction, _cts.Token)
}

Categories

Resources