Плавная остановка потоков
Здравствуйте подскажите как правильно остановить потоки, если при завершение я останавливаю потоки данным кодом, я получаю исключение ThreadException и при этом, так как ошибка прерывания потоков, последние данные у меня не обрабатываются... Метод старта
void workStart()
{
LifeThread = true;
ListThread.Clear();
for (int i = 0; i < 5; i++)
{
Thread td = new Thread(work);
ListThread.Add(td);
td.Start();
}
btn_Start.Enabled = false;
btn_Stop.Enabled = true;
}
Рабочая функция
private void work()
{
while (User_Data.Count - 1 >= Log._index && LifeThread)
{
St();
}
Invoke((MethodInvoker)delegate
{
Stop();
});
}
Метод остановки потоков
void Stop()
{
LifeThread = false;
foreach (Thread thread in ListThread)
thread.Abort();
btn_Stop.Enabled = false;
btn_Start.Enabled = true;
MessageBox.Show("OFF Work", "Status");
}
Ответы (1 шт):
Вы совершенно не правильно завершаете потоки. Вы завершаете другие потоки внутри 1-го потока, учитывая этот сам поток. Используйте Task – целее будете.
static void Main()
{
var task = RunTasks(5);
task.Wait();
}
static Task RunTasks(int count)
{
var tasks = new Task[count];
var syncRoot = new object();
var cts = new CancellationTokenSource();
for (var i = 0; i < count; i++)
tasks[i] = Run(tasks, i, syncRoot, cts);
var task = Task.WhenAll(tasks); // аналогично `WhenAny`
task.ContinueWith(t => cts.Dispose());
return task;
}
static async Task Run(Task[] tasks, int id, object syncRoot, CancellationTokenSource cancellationTokenSource)
{
var parTask = Task.Run(() => { });
await parTask;
MessageBox.Show($"Task #{id} is running...");
var stopwatch = new Stopwatch();
stopwatch.Start();
try { await Task.Delay(id * 1000 + 1000, cancellationTokenSource.Token); } // some work
catch (OperationCanceledException) { }
stopwatch.Stop();
if (cancellationTokenSource.IsCancellationRequested)
{
MessageBox.Show($"Task #{id} cancelled at {stopwatch.ElapsedMilliseconds} ms");
return;
}
MessageBox.Show($"Task #{id} completed at {stopwatch.ElapsedMilliseconds} ms");
lock (syncRoot)
{
if (cancellationTokenSource.IsCancellationRequested) return;
foreach (var task in tasks)
if (task.Id != Task.CurrentId)
cancellationTokenSource.Cancel();
}
}
Тут запускается 5 задач, когда 1 завершается, происходит отмена остальных. "Прямая отмена" заменена на отмену через CancellationTokenSource.
Примечание: Не используйте WhenAll, если в этом нет необходимости: здесь этот метод используется в демонстративных целях.