В потоке я создаю некоторые System.Threading.Task
и запускаю каждую задачу.
Когда я делаю, .Abort()
чтобы убить поток, задачи не прерываются.
Как я могу передать .Abort()
свои задачи?
В потоке я создаю некоторые System.Threading.Task
и запускаю каждую задачу.
Когда я делаю, .Abort()
чтобы убить поток, задачи не прерываются.
Как я могу передать .Abort()
свои задачи?
Ответы:
Ты не можешь Задачи используют фоновые потоки из пула потоков. Также не рекомендуется отменять темы с помощью метода Abort. Вы можете взглянуть на следующий пост в блоге, который объясняет правильный способ отмены задач с использованием токенов отмены. Вот пример:
class Program
{
static void Main()
{
var ts = new CancellationTokenSource();
CancellationToken ct = ts.Token;
Task.Factory.StartNew(() =>
{
while (true)
{
// do some heavy work here
Thread.Sleep(100);
if (ct.IsCancellationRequested)
{
// another thread decided to cancel
Console.WriteLine("task canceled");
break;
}
}
}, ct);
// Simulate waiting 3s for the task to complete
Thread.Sleep(3000);
// Can't wait anymore => cancel this task
ts.Cancel();
Console.ReadLine();
}
}
Task.Wait(TimeSpan / int)
чтобы назначить (основанный на времени) крайний срок извне.
Task
? Что - то вроде: public int StartNewTask(Action method)
. Внутри StartNewTask
метода я создаю новый Task
по: Task task = new Task(() => method()); task.Start();
. Так как я могу управлять CancellationToken
? Я также хотел бы знать, если Thread
мне нужно реализовать логику, чтобы проверить, есть ли какие-то задачи, которые все еще висят, и поэтому убить их, когда Form.Closing
. С Threads
я использую Thread.Abort()
.
Прерывание задачи легко возможно, если вы захватываете поток, в котором выполняется задача. Вот пример кода, демонстрирующий это:
void Main()
{
Thread thread = null;
Task t = Task.Run(() =>
{
//Capture the thread
thread = Thread.CurrentThread;
//Simulate work (usually from 3rd party code)
Thread.Sleep(1000);
//If you comment out thread.Abort(), then this will be displayed
Console.WriteLine("Task finished!");
});
//This is needed in the example to avoid thread being still NULL
Thread.Sleep(10);
//Cancel the task by aborting the thread
thread.Abort();
}
Я использовал Task.Run (), чтобы показать наиболее распространенный вариант использования этого - использование удобства Tasks со старым однопоточным кодом, который не использует класс CancellationTokenSource, чтобы определить, следует ли его отменить или нет.
CancellationToken
поддерживает ...
CancellationToken
или даже более простые решения, которые не содержат условий гонки, должны быть рассмотрены. Приведенный выше код только иллюстрирует метод, а не область использования.
thread
локальной переменной). В вашем коде вы можете в итоге прервать основной поток, а это не то, что вам действительно нужно. Возможно, было бы неплохо проверить, совпадают ли потоки перед прерыванием, если вы настаиваете на прерывании
Как следует из этого поста , это можно сделать следующим образом:
int Foo(CancellationToken token)
{
Thread t = Thread.CurrentThread;
using (token.Register(t.Abort))
{
// compute-bound work here
}
}
Хотя это работает, не рекомендуется использовать такой подход. Если вы можете контролировать код, который выполняется в задаче, вам лучше использовать правильную обработку отмены.
Подобные вещи являются одной из материально-технических причин, почему Abort
это устарело. Прежде всего, не используйте Thread.Abort()
для отмены или остановки потока, если это вообще возможно. Abort()
следует использовать только для принудительного уничтожения потока, который не отвечает на более мирные запросы о своевременной остановке.
При этом вам необходимо предоставить общий индикатор отмены, который один поток устанавливает и ожидает, пока другой поток периодически проверяет и корректно завершает работу. .NET 4 включает структуру, разработанную специально для этой цели CancellationToken
.
Вы не должны пытаться сделать это напрямую. Создайте свои задачи для работы с CancellationToken и отмените их таким образом.
Кроме того, я бы порекомендовал изменить основной поток, чтобы он функционировал через CancellationToken. Звонить Thread.Abort()
- плохая идея - это может привести к различным проблемам, которые очень сложно диагностировать. Вместо этого, что поток может использовать один и тот же Аннулирование , что ваши задачи использовать - и то же самое CancellationTokenSource
может быть использован , чтобы вызвать отмену всех ваших задач и ваш основной поток.
Это приведет к гораздо более простому и безопасному дизайну.
Чтобы ответить на вопрос Prerak K о том, как использовать CancellationTokens, когда не используется анонимный метод в Task.Factory.StartNew (), вы передаете CancellationToken в качестве параметра в метод, который вы начинаете с StartNew (), как показано в примере MSDN сюда .
например
var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
Task.Factory.StartNew( () => DoSomeWork(1, token), token);
static void DoSomeWork(int taskNum, CancellationToken ct)
{
// Do work here, checking and acting on ct.IsCancellationRequested where applicable,
}
Я использую смешанный подход, чтобы отменить задачу.
Проверьте пример ниже:
private CancellationTokenSource taskToken;
private AutoResetEvent awaitReplyOnRequestEvent = new AutoResetEvent(false);
void Main()
{
// Start a task which is doing nothing but sleeps 1s
LaunchTaskAsync();
Thread.Sleep(100);
// Stop the task
StopTask();
}
/// <summary>
/// Launch task in a new thread
/// </summary>
void LaunchTaskAsync()
{
taskToken = new CancellationTokenSource();
Task.Factory.StartNew(() =>
{
try
{ //Capture the thread
runningTaskThread = Thread.CurrentThread;
// Run the task
if (taskToken.IsCancellationRequested || !awaitReplyOnRequestEvent.WaitOne(10000))
return;
Console.WriteLine("Task finished!");
}
catch (Exception exc)
{
// Handle exception
}
}, taskToken.Token);
}
/// <summary>
/// Stop running task
/// </summary>
void StopTask()
{
// Attempt to cancel the task politely
if (taskToken != null)
{
if (taskToken.IsCancellationRequested)
return;
else
taskToken.Cancel();
}
// Notify a waiting thread that an event has occurred
if (awaitReplyOnRequestEvent != null)
awaitReplyOnRequestEvent.Set();
// If 1 sec later the task is still running, kill it cruelly
if (runningTaskThread != null)
{
try
{
runningTaskThread.Join(TimeSpan.FromSeconds(1));
}
catch (Exception ex)
{
runningTaskThread.Abort();
}
}
}
Задачи имеют первоклассную поддержку отмены через токены отмены . Создайте свои задачи с токенами отмены, и отмените задачи через них явно.
Вы можете использовать CancellationToken
для контроля отмены задачи. Вы говорите о том, чтобы прервать его до его начала («неважно, я уже сделал это») или фактически прерываете его посередине? Если первое, то CancellationToken
может быть полезно; в последнем случае вам, вероятно, потребуется реализовать свой собственный механизм «спасения» и проверить в соответствующих точках выполнения задачи, следует ли вам быстро потерпеть неудачу (вы все равно можете использовать CancellationToken, чтобы помочь вам, но это немного больше ручного управления).
В MSDN есть статья об отмене задач: http://msdn.microsoft.com/en-us/library/dd997396.aspx
Задачи выполняются в ThreadPool (по крайней мере, если вы используете фабрику по умолчанию), поэтому прерывание потока не может повлиять на задачи. Для отмены задач см. Отмена задач на msdn.
Я пытался, CancellationTokenSource
но я не могу этого сделать. И я сделал это по-своему. И это работает.
namespace Blokick.Provider
{
public class SignalRConnectProvider
{
public SignalRConnectProvider()
{
}
public bool IsStopRequested { get; set; } = false; //1-)This is important and default `false`.
public async Task<string> ConnectTab()
{
string messageText = "";
for (int count = 1; count < 20; count++)
{
if (count == 1)
{
//Do stuff.
}
try
{
//Do stuff.
}
catch (Exception ex)
{
//Do stuff.
}
if (IsStopRequested) //3-)This is important. The control of the task stopping request. Must be true and in inside.
{
return messageText = "Task stopped."; //4-) And so return and exit the code and task.
}
if (Connected)
{
//Do stuff.
}
if (count == 19)
{
//Do stuff.
}
}
return messageText;
}
}
}
И еще один класс вызова метода:
namespace Blokick.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MessagePerson : ContentPage
{
SignalRConnectProvider signalR = new SignalRConnectProvider();
public MessagePerson()
{
InitializeComponent();
signalR.IsStopRequested = true; // 2-) And this. Make true if running the task and go inside if statement of the IsStopRequested property.
if (signalR.ChatHubProxy != null)
{
signalR.Disconnect();
}
LoadSignalRMessage();
}
}
}
Вы можете прервать задачу как поток, если можете заставить задачу быть созданной в ее собственном потоке и вызвать Abort
ее Thread
объект. По умолчанию задача выполняется в потоке пула потоков или в вызывающем потоке - ни один из которых вы обычно не хотите прерывать.
Чтобы задача получила собственный поток, создайте собственный планировщик, полученный из TaskScheduler
. В вашей реализации QueueTask
создайте новый поток и используйте его для выполнения задачи. Позже вы можете прервать поток, что приведет к завершению задачи в ошибочном состоянии с помощью ThreadAbortException
.
Используйте этот планировщик задач:
class SingleThreadTaskScheduler : TaskScheduler
{
public Thread TaskThread { get; private set; }
protected override void QueueTask(Task task)
{
TaskThread = new Thread(() => TryExecuteTask(task));
TaskThread.Start();
}
protected override IEnumerable<Task> GetScheduledTasks() => throw new NotSupportedException(); // Unused
protected override bool NotSupportedException(Task task, bool taskWasPreviouslyQueued) => throw new NotSupportedException(); // Unused
}
Начните свою задачу так:
var scheduler = new SingleThreadTaskScheduler();
var task = Task.Factory.StartNew(action, cancellationToken, TaskCreationOptions.LongRunning, scheduler);
Позже вы можете прервать с помощью:
scheduler.TaskThread.Abort();
Обратите внимание, что предупреждение об прерывании потока все еще применяется:
Thread.Abort
Метод следует использовать с осторожностью. В частности, когда вы вызываете его для прерывания потока, отличного от текущего потока, вы не знаете, какой код был выполнен или не удалось выполнить, когда выдается исключение ThreadAbortException , а также вы не можете быть уверены в состоянии вашего приложения или любого приложения и пользовательского состояния. что он отвечает за сохранение. Например, вызовThread.Abort
может препятствовать выполнению статических конструкторов или препятствовать освобождению неуправляемых ресурсов.
Thread.Abort
она не поддерживается в .NET Core. Попытка его использования приводит к исключению: System.PlatformNotSupportedException: прерывание потока не поддерживается на этой платформе. Третье предостережение заключается в том, что SingleThreadTaskScheduler
его нельзя эффективно использовать с задачами в стиле обещания, другими словами, с задачами, созданными с async
делегатами. Например, встроенное выполнение await Task.Delay(1000)
выполняется без потока, поэтому оно не подвержено влиянию событий потока.