С# как моментально остановить поток?
Запускаю одновременно несколько тасков:
using (semaphore = new SemaphoreSlim(maxConcurrency))
{
List<Task> tasks = new List<Task>();
for (int i = 0; i < MyCollection.Count; i++)
{
int id = i;
await semaphore.WaitAsync();
tasks.Add(Task.Run(() =>
{
progress.Report("Автопостинг, канал : " + 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("Поток " + ChanelNubmer + " остановлен!");
MyCollection[ChanelNubmer].Status = "Не работает";
return;
}
}
}
Метод выполняет определенную работу, затем ждет 200000 миллисекунд и повторяет действие заново.
Если нужно остановить работу метода - нажатием кнопки на форме я присваиваю логической переменной Stop значение true
Проблема в том что используя Task.Delay(200000); - цикл будет остановлен не сразу.
Как в данном случае можно остановить работу метода моментально?
И метод AddPost я запускаю одновременно в нескольких потоках, если присвоить Stop == true - остановятся все потоки, можно как то обратиться к определенному потоку что бы остановить только его?
Ответы (1 шт):
Используйте 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;