Почему мой код выдает исключение `Семафор удален`? - PullRequest
1 голос
/ 18 июня 2019

В моем коде я использую SemaphoreSlim и после выполнения всего цикла for я получаю от App.g.cs исключение The semaphore has been disposed, и я не могу выяснить, почему, если он удаляется только usingзаявление.Вот код всего метода, который используется:

public async Task TestHistoricalResultsAsync()
{
    //init values and controls
    CommandStartedControlsSetup("TestResultsCommand");

    List<Task> tasks = new List<Task>();
    int degreeOfParallelism = 10;
    int loopCounter = 0;
    ProgressBarTick("Testing on historic data", loopCounter, Races.Count, 0);
    using (var throttler = new SemaphoreSlim(degreeOfParallelism))
    {
        //for all races in the file
        for (int i = 0; i < Races.Count; i++)
        {
            int j = i;

            if (TaskCancellation == true)
            {
                break;
            }

            await throttler.WaitAsync(TokenSource.Token);

            tasks.Add(Task.Run(() => //async
            {
                try
                {
                    CancellationToken.ThrowIfCancellationRequested();

                    //if the race is from 2018
                    if (Races[j].RaceDate.Year == 2018)
                    {
                        Category = Races[j].RaceCategory;
                        Distance = Races[j].RaceDistance.ToString();

                        //for all horses in the race
                        for (int h = 0; h < Races[j].HorseList.Count; h++)
                        {
                            if (TaskCancellation == true)
                            {
                                break;
                            }
                            CancellationToken.ThrowIfCancellationRequested();
                            HorseDataWrapper horse = new HorseDataWrapper();
                            horse = ParseHorseData(Races[j].HorseList[h], Races[j].RaceDate);
                            Races[j].HorseList[h] = horse; //get all indexes
                        }
                    }
                }
                catch (Exception e)
                {
                    //
                }
                finally
                {
                    loopCounter++;

                    ProgressBarTick("Testing on historic data", loopCounter, Races.Count, 0);

                    throttler.Release();
                }
            }));
        }
    }
    try
    {
        //ThreadPool.SetMinThreads(100, 100);
        await Task.WhenAll(tasks);
    }
    catch (OperationCanceledException)
    {
        //
    }
    finally
    {
        await _dataServices.SaveRaceTestResultsAsync(Races.ToList()); //save the analysis to the file

        AllControlsEnabled = true;

        CommandCompletedControlsSetup();

        VisibilityCancellingMsg = Visibility.Collapsed;
    }
}

1 Ответ

2 голосов
/ 18 июня 2019

Что касается обсуждения комментариев, проблема в том, что ваш семафор выходит из области видимости.У вас есть два варианта:

a) Ожидать выполнения всех задач внутри блока

using (var throttler = new SemaphoreSlim(degreeOfParallelism))
{
    // setup the tasks

    try
    {
        await Task.WhenAll(tasks);
    }
    // ...
}

b) Утилизировать вручную после завершения выполнения всех задач

var throttler = new SemaphoreSlim(degreeOfParallelism)
{
    // setup the tasks. You can still use a scope block (brackets) here if you want.
}

try
{
    await Task.WhenAll(tasks);
    // ...
}
finally 
{
    throttler?.Dispose()
}

Второй вариант, скорее всего, будет более подходящим, но он зависит от окончательной компоновки вашего кода.

...