Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exception while running System.Threading.Tasks.Task

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?

like image 205
Serve Laurijssen Avatar asked Apr 04 '13 06:04

Serve Laurijssen


People also ask

How do you handle exceptions thrown by tasks?

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.

What is task in threading?

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.

Are tasks and threads the same?

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.

Why we use using system threading tasks in C#?

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.


1 Answers

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:

  • don't let your tasks throw,
  • or make sure that you're there to check the status of the task later

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.

like image 189
Marc Gravell Avatar answered Sep 28 '22 07:09

Marc Gravell