Sephystos
Sephystos

Reputation: 69

Wait for the end of an asynchronous task

I have a task that runs asynchronously, and I have a second method, right after that, that needs to retrieve the information from the asynchronous task. I can't modify the asynchronous task, so I wanted to know if it's possible to tell the second method to wait until the asynchronous method is finished.

foreach (AgentModel ag in Agents)
{
    if (ag.IsEnabledRow == true)
    {
        if (ag.IsSelected == true)
        {
            if (ag.selectedMatrice != null)
            {
                if (ag.selectedWeeks != null)
                {
                    //on vérifie le cycle choisi et on adapte la date en conséquence
                    semaineAAppliquer(ag);

                    ag.IsEnabledRow = false;

                    Task<int> attribuerPlanning = Gestion.AttrPlanning(
                        _dataService.ParamGlobaux.IDEtablissement,
                        _dataService.ParamGlobaux.Matricule,
                        _dataService.ParamGlobaux.ConnectionString,
                        ag.Matricule, ag.selectedMatrice.IDMatrice, DsCalendrierCongés,
                        dateDebutCycle, ag.dateFin, HoraireAZero, CompleterPriseVide,
                        RemplacerRH, JFRepos,
                        (text, title, buttons) => System.Windows.MessageBox.Show(
                            text, title, buttons), _progress, DecalageSemaine,
                            appliquerCouleur, _ToutEtablissement);
                }
            }
            else
            {
                System.Windows.MessageBox.Show($"Sélectionner une matrice pour" +
                    $" l'agent {ag.Nom}.");
            }
        }
    }
}

UpdateListeContrats();

The attribuerPlanning method is the asynchronous method, and I would like, without modifying the method itself, that it ends before calling UpdateListeContrats.

Or a way of saying UpdateListeContrats, don't trigger yourself until the other method is complete.

(Currently, updateListeContrats launches without having the information updated by the attributerPlanning method.)

Upvotes: 1

Views: 261

Answers (2)

zsolt
zsolt

Reputation: 1611

UPDATE: As Marc pointed out, don't do this if you have something that shouldn't or mustn't be blocked in the main thread, like a GUI.

You can do attribuerPlanning.Wait(); after calling it.

Or if you want to run all task in the foreach async and wait all task to finish before UpdateListeContrats you can create a task list outside of the foreach:

List<Task> tasks = new List<Task>();

and in the loop body add the current task to the list:

var task = Task.Run(() => Gestion.AttrPlanning(...) );
tasks.Add(task);

and outside of foreach do

Task.WhenAll(tasks).Wait();
UpdateListeContrats();

Upvotes: -1

Marc Gravell
Marc Gravell

Reputation: 1062492

Firstly, you should virtually never "wait" (synchronous) for a task, but it is fine to "await" it (asynchronous).

In this case, the most appropriate place to do this is probably: at the call site, i.e.

if (ag.selectedWeeks != null)
{
    //on vérifie le cycle choisi et on adapte la date en conséquence
    semaineAAppliquer(ag);

    ag.IsEnabledRow = false;

    var result = await Gestion.AttrPlanning( ... );
}

In addition to being simple, this also avoids concurrency issues; most code is not anticipating concurrent usage in the same context.

In the general case, you can capture the task (etc) at one place, and await it later, but in your case the problem becomes what to do about the foreach/if etc; there could be zero, one, or many such tasks, if you are running them concurrently. But I guess you could throw them in a list, i.e.

var pending = new List<Task<int>>();
// ...
            pending.Add(attribuerPlanning);
// ...
var results = await Task.WhenAll(pending);

Upvotes: 5

Related Questions