Consider the following code which uses basic Task library functionality with a CancellationTokenSource. It starts up a thread which fills a Dictionary with prices and reads the data from an SQL server db. The thread ends after about 10 minutes and every 2 hours it is fired up again, calling Cancel first in case the thread was still running.
private CancellationTokenSource mTokenSource = new CancellationTokenSource();
internal Prices(Dictionary<string, Dealer> dealers)
{
mDealers = dealers;
mTask = Task.Factory.StartNew
(() => ReadPrices(mTokenSource.Token), mTokenSource.Token);
}
internal void Cancel()
{
mTokenSource.Cancel();
}
private void ReadPrices(CancellationToken ct)
{
using (SqlConnection connection =
new SqlConnection(ConfigurationManager.AppSettings["DB"]))
{
connection.Open();
var dealerIds = from dealer in mDealers.Values
where dealer.Id != null
select dealer.Id;
foreach (var dealerId in dealerIds)
{
if (!ct.IsCancellationRequested)
{
FillPrices(connection);
}
else
break;
}
}
}
Now at some point the application crashes with the following exception in the event log.
Application: Engine.exe Framework Version: v4.0.30319 Description: The process was terminated due to an unhandled exception. Exception Info: System.AggregateException Stack: at System.Threading.Tasks.TaskExceptionHolder.Finalize()
It must have to do with the code here because the Tasks library isn't used anywhere else but I cant figure out what is wrong with the code. Does anyone have an idea what could be wrong here?
Exceptions are propagated when you use one of the static or instance Task. Wait methods, and you handle them by enclosing the call in a try / catch statement. If a task is the parent of attached child tasks, or if you are waiting on multiple tasks, multiple exceptions could be thrown.
A task is something you want done. A thread is one of the many possible workers which performs that task. In . NET 4.0 terms, a Task represents an asynchronous operation. Thread(s) are used to complete that operation by breaking the work up into chunks and assigning to separate threads.
Differences Between Task And ThreadThe Thread class is used for creating and manipulating a thread in Windows. A Task represents some asynchronous operation and is part of the Task Parallel Library, a set of APIs for running tasks asynchronously and in parallel. The task can return a result.
Tasks Namespace. Provides types that simplify the work of writing concurrent and asynchronous code. The main types are Task which represents an asynchronous operation that can be waited on and cancelled, and Task<TResult>, which is a task that can return a value.
Tasks like to feel listened to. It sounds like something isn't happy. You do get a "last chance" to hear it out, though:
TaskScheduler.UnobservedTaskException += (sender, args) =>
{
foreach (var ex in args.Exception.InnerExceptions)
{
Log(ex);
}
args.SetObserved();
};
Note this isn't intended as the fix - it is intended to let you see what Task
is exploding and with what error. The SetObserved()
will prevent it killing your application. But the fix here is ideally:
It is quite possibly not happy with your cancellation detection. IIRC the preferred way to do that would be:
foreach(...) {
if(ct.IsCancellationRequested) {
// any cleanup etc
ct.ThrowIfCancellationRequested();
}
...
}
or more simply if no cleanup is needed, just:
foreach(...) {
ct.ThrowIfCancellationRequested();
...
}
Equally, it could just be a data access exception. There are any number of exceptions that can happen when talking to a database. Timeout, deadlock, cannot-connect, etc.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With