c# Async function - try to sum values in foreach loop

Viewed 748

i have a problem with CalcTime function, i try to sum all values from events in async way but i get a wrong value, i want to gets 60 seconds but i gets different value every run:

async Task main()
{
    // do stuff
    Task timeTask = class1.CalcTime();
    await Task.WhenAll(timeTask);

}

public class class1 {
    // In events lists have 6 events and each event is 10 seconds
    public async Task CalcTime()
    {
        double actTime  = 0;
        List<Task<double>> list = new List<Task<double>>();
        foreach (Event event in events)
        {
            list.Add(Task.Run(() => actTime += ReturnTime(event)));
        }    

            await Task.WhenAll(list);
        
            // actTime gets a different value in each run, why?
    }

    public double ReturnTime(Event event)
    {
       return event.Time;
    }

}

why it's happen? and how to fix it?

and more question, if i use Task.WhenAll inside function and after i call this function in main function i need to set Task.WhenAll also in main to this specific function? or is it enough to call it just in function?

and if i using await word with Task.WhenAll so the function is stop until all the job done or Task.WhenAll waiting that all jobs done and at the same time the thread is available for another job and can continue work in main function?

Thanks!

1 Answers

As canton7 said in a comment, you can avoid all thread-safety traps by collecting the result of each Task<double>, and summing the partial results after all tasks have completed. This way the tasks will not step on each other toes, by trying to update a shared variable in an unsynchronized fashion.

var tasks = new List<Task<double>>();
foreach (var event in events)
{
    tasks.Add(Task.Run(() => ReturnTime(event)));
}    
double[] results = await Task.WhenAll(tasks);
double actTime = results.Sum();
Related