1

Запускаю одновременно несколько тасков:

using (semaphore = new SemaphoreSlim(maxConcurrency))
{
    List<Task> tasks = new List<Task>();
for (int i = 0; i &lt; MyCollection.Count; i++)
{
    int id = i;
    await semaphore.WaitAsync();  

    tasks.Add(Task.Run(() =&gt;
    {
          progress.Report(&quot;Автопостинг, канал : &quot; + id);

          AddPost(progress, id, semaphore, false);
     }));

 }

 StatusWork = true;

  await Task.WhenAll(tasks);

}

Метод AddPost() выглядит примерно вот так:

 public async void AddPost(IProgress<string> progress, int ChanelNubmer, SemaphoreSlim semaphore, bool IndividualStartCheck)
    {
        for (; ; )
        {
            // Полезная нагрузка 
            Task.Delay(200000);
        if (Stop == true)
        {
            progress.Report(&quot;Поток &quot; + ChanelNubmer + &quot; остановлен!&quot;);
            MyCollection[ChanelNubmer].Status = &quot;Не работает&quot;;
            return;
        }
    }
}

Метод выполняет определенную работу, затем ждет 200000 миллисекунд и повторяет действие заново.

Если нужно остановить работу метода - нажатием кнопки на форме я присваиваю логической переменной Stop значение true

Проблема в том что используя Task.Delay(200000); - цикл будет остановлен не сразу.

Как в данном случае можно остановить работу метода моментально?

И метод AddPost я запускаю одновременно в нескольких потоках, если присвоить Stop == true - остановятся все потоки, можно как то обратиться к определенному потоку что бы остановить только его?

WyWyWy
  • 55
  • 6
  • https://ru.stackoverflow.com/q/1257633/213987 – A K Apr 21 '21 at 14:43
  • Task.Delay(200000); вот здесь вы забыли про await. У вас приложение не виснет от запуска кучи Delay в секунду, случаем? Да и semaphore.Release() вы забыли вызывать при завершении операции. – aepot Apr 21 '21 at 16:56
  • aepot, Создаю 10 тасков с методом AddPost, приложение не виснет, я правильно понимаю что использую return - я останавливаю цикл for (; ; ), а для того что бы убить таск - нужно использовать semaphore.Release() ? Спасибо – WyWyWy Apr 21 '21 at 18:57

1 Answers1

4

Используйте CancellationToken.

async void нельзя ожидать, поэтому вся ваша конструкция с семафором не имела никакого смысла.

Асинхронное программирование - прочитайте обязательно.

public async Task AddPost(IProgress<string> progress, int channelNumber, SemaphoreSlim semaphore, bool individualStartCheck, CancellationToken token)
{
    progress.Report("Автопостинг, канал : " + channelNumber);
    try
    {
        for (;;)
        {
            // Полезная нагрузка 
            await Task.Delay(200000, token);
        }
    }
    catch (OperationCanceledException)
    { }
    finally
    {
        semaphore.Release();
    }
    progress.Report("Поток " + channelNumber + " остановлен!");
    MyCollection[channelNumber].Status = "Не работает";
}

Далее объявите CancellationTokenSource

private CancellationTokenSource _cts;

И вот так это использовать

if (_cts != null)
    return;

using (_cts = new CancellationTokenSource()) using (SemaphoreSlim semaphore = new SemaphoreSlim(maxConcurrency)) { List<Task> tasks = new List<Task>(); try { for (int i = 0; i < MyCollection.Count; i++) { await semaphore.WaitAsync(_cts.Token);

        tasks.Add(AddPost(progress, i, semaphore, false, _cts.Token));
    }
}
catch (OperationCanceledException)
{ }
await Task.WhenAll(tasks);

} _cts = null;

Чтобы всё остановить, просто вызовите

_cts?.Cancel();

При срабатывании отмены, асинхронные методы .NET бросают исключение OperationCanceledException, его нужно всего-лишь поймать. При желании вы так же внутри своих методов можете его бросить вот так:

token.ThrowIfCancellationRequested();

Или без выбрасывания исключения делать проверку типа

if (token.IsCancellationRequested)
    return;
aepot
  • 49,560