Das kannst du nicht. Aufgaben verwenden Hintergrundthreads aus dem Threadpool. Das Abbrechen von Threads mit der Abort-Methode wird ebenfalls nicht empfohlen. Sie können sich den folgenden Blog-Beitrag ansehen, in dem erläutert wird, wie Aufgaben mithilfe von Stornierungs-Token ordnungsgemäß abgebrochen werden. Hier ist ein Beispiel:
classProgram{staticvoidMain(){var ts =newCancellationTokenSource();CancellationToken ct = ts.Token;Task.Factory.StartNew(()=>{while(true){// do some heavy work hereThread.Sleep(100);if(ct.IsCancellationRequested){// another thread decided to cancelConsole.WriteLine("task canceled");break;}}}, ct);// Simulate waiting 3s for the task to completeThread.Sleep(3000);// Can't wait anymore => cancel this task
ts.Cancel();Console.ReadLine();}}
Schöne Erklärung. Ich habe eine Frage, wie funktioniert es, wenn wir keine anonyme Methode in Task.Factory.StartNew haben? wie Task.Factory.StartNew (() => ProcessMyMethod (), CancellationToken)
Prerak K
61
Was ist, wenn es einen blockierenden Aufruf gibt, der innerhalb der ausgeführten Aufgabe nicht zurückkehrt?
mehmet6parmak
3
@ mehmet6parmak Ich denke, das einzige, was Sie dann tun können, ist Task.Wait(TimeSpan / int), ihm eine (zeitbasierte) Frist von außen zu geben.
Mark
2
Was ist, wenn ich meine benutzerdefinierte Klasse habe, um die Ausführung von Methoden in einer neuen zu verwalten Task? So etwas wie : public int StartNewTask(Action method). Innerhalb der StartNewTaskMethode erstelle ich eine neue Taskvon : Task task = new Task(() => method()); task.Start();. Wie kann ich das verwalten CancellationToken? Ich würde auch gerne wissen, ob Threadich eine Logik implementieren muss, um zu überprüfen, ob noch einige Aufgaben hängen, und sie dann zu töten, wenn Form.Closing. Mit Threadsich benutze Thread.Abort().
Cheshire Cat
Omg, was für ein schlechtes Beispiel! Es ist eine einfache boolesche Bedingung, natürlich ist es die erste, die man versuchen würde! Aber dh ich habe eine Funktion in einer separaten Aufgabe, deren Beendigung viel Zeit in Anspruch nehmen kann, und im Idealfall sollte sie nichts über ein Threading oder was auch immer wissen. Wie kann ich die Funktion mit Ihrem Rat abbrechen?
Hi-Angel
32
Das Abbrechen einer Aufgabe ist problemlos möglich, wenn Sie den Thread erfassen, in dem die Aufgabe ausgeführt wird. Hier ein Beispielcode, um dies zu demonstrieren:
voidMain(){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 displayedConsole.WriteLine("Task finished!");});//This is needed in the example to avoid thread being still NULLThread.Sleep(10);//Cancel the task by aborting the thread
thread.Abort();}
Ich habe Task.Run () verwendet, um den häufigsten Anwendungsfall dafür anzuzeigen - unter Verwendung des Komforts von Aufgaben mit altem Single-Threaded-Code, bei dem die CancellationTokenSource-Klasse nicht verwendet wird, um zu bestimmen, ob sie abgebrochen werden soll oder nicht.
Danke für diese Idee. Verwendete diesen Ansatz, um eine Zeitüberschreitung für einen externen Code zu implementieren, der keine CancellationTokenUnterstützung hat ...
Christoph Fink
7
AFAIK thread.abort lässt Sie über Ihren Stapel unbekannt, es könnte ungültig sein. Ich habe es noch nie versucht, aber ich denke, ein Thread in einer separaten App-Domain zu starten, der thread.abort gespeichert wird! Außerdem wird in Ihrer Lösung ein ganzer Thread verschwendet, um nur eine Aufgabe abzubrechen. Sie müssten zunächst keine Aufgaben, sondern Threads verwenden. (Downvote)
Martin Meeser
1
Wie ich schrieb - diese Lösung ist ein letzter Ausweg, der unter bestimmten Umständen in Betracht gezogen werden könnte. Natürlich sollten eine CancellationTokenoder noch einfachere Lösungen in Betracht gezogen werden, die frei von Rennbedingungen sind. Der obige Code veranschaulicht nur die Methode, nicht den Anwendungsbereich.
Florian Rappl
8
Ich denke, dieser Ansatz könnte unbekannte Konsequenzen haben und ich würde ihn im Produktionscode nicht empfehlen. Es wird nicht immer garantiert, dass Aufgaben in einem anderen Thread ausgeführt werden. Dies bedeutet, dass sie in demselben Thread ausgeführt werden können, in dem sie erstellt wurden, wenn der Scheduler dies entscheidet (was bedeutet, dass der Hauptthread an die threadlokale Variable übergeben wird). In Ihrem Code wird der Hauptthread möglicherweise abgebrochen, was nicht wirklich gewünscht ist. Vielleicht wäre eine Überprüfung, ob die Threads vor dem Abbruch gleich sind, eine gute Idee, wenn Sie darauf bestehen, abzubrechen
Ivaylo Slavov
10
@Martin - Da ich diese Frage zu SO recherchiert habe, habe ich festgestellt, dass Sie mehrere Antworten, die Thread.Abort zum Beenden von Aufgaben verwenden, abgelehnt haben, aber keine alternativen Lösungen bereitgestellt haben. Wie können Sie Code von Drittanbietern beenden, der die Stornierung nicht unterstützt und in einer Aufgabe ausgeführt wird ?
intFoo(CancellationToken token){Thread t =Thread.CurrentThread;
using (token.Register(t.Abort)){// compute-bound work here}}
Obwohl es funktioniert, wird nicht empfohlen, einen solchen Ansatz zu verwenden. Wenn Sie den Code steuern können, der in der Aufgabe ausgeführt wird, sollten Sie die Stornierung ordnungsgemäß behandeln.
+1 für einen anderen Ansatz bei der Angabe der Fallbacks. Ich wusste nicht, dass dies möglich ist :)
Joel
1
Danke für die Lösung! Wir können das Token einfach an die Methode übergeben und die Tokenquelle abbrechen, anstatt irgendwie die Thread-Instanz von der Methode abzurufen und diese Instanz direkt abzubrechen.
Diese Art von Dingen ist einer der logistischen Gründe, warum sie Abortveraltet sind. Verwenden Sie Thread.Abort()in erster Linie nicht , um einen Thread abzubrechen oder zu stoppen, wenn dies überhaupt möglich ist. Abort()sollte nur verwendet werden, um einen Thread gewaltsam zu beenden, der nicht auf friedlichere Anfragen reagiert, rechtzeitig anzuhalten.
Davon abgesehen müssen Sie einen gemeinsamen Abbruchindikator bereitstellen, den ein Thread setzt und wartet, während der andere Thread regelmäßig prüft und ordnungsgemäß beendet. .NET 4 enthält eine speziell für diesen Zweck entwickelte Struktur, die CancellationToken.
Sie sollten dies nicht direkt versuchen. Entwerfen Sie Ihre Aufgaben so, dass sie mit einem CancellationToken arbeiten , und brechen Sie sie auf diese Weise ab.
Außerdem würde ich empfehlen, Ihren Hauptthread so zu ändern, dass er auch über ein CancellationToken funktioniert. Anrufen Thread.Abort()ist eine schlechte Idee - es kann zu verschiedenen Problemen führen, die sehr schwer zu diagnostizieren sind. Stattdessen kann dieser Thread dieselbe Stornierung verwenden , die Ihre Aufgaben verwenden - und dieselbe CancellationTokenSourcekann verwendet werden, um die Stornierung aller Ihrer Aufgaben und Ihres Hauptthreads auszulösen .
Dies führt zu einem weitaus einfacheren und sichereren Design.
Um die Frage von Prerak K zur Verwendung von CancellationTokens zu beantworten, wenn in Task.Factory.StartNew () keine anonyme Methode verwendet wird, übergeben Sie das CancellationToken als Parameter an die Methode, die Sie mit StartNew () beginnen, wie im MSDN-Beispiel gezeigt Hier .
z.B
var tokenSource =newCancellationTokenSource();var token = tokenSource.Token;Task.Factory.StartNew(()=>DoSomeWork(1, token), token);staticvoidDoSomeWork(int taskNum,CancellationToken ct){// Do work here, checking and acting on ct.IsCancellationRequested where applicable, }
Wenn es noch läuft (z. B. aufgrund eines Entwicklerfehlers), verhalten Sie sich schlecht und beenden Sie es mit einer Abort- Methode der alten Schule .
Kasse ein Beispiel unten:
privateCancellationTokenSource taskToken;privateAutoResetEvent awaitReplyOnRequestEvent =newAutoResetEvent(false);voidMain(){// Start a task which is doing nothing but sleeps 1sLaunchTaskAsync();Thread.Sleep(100);// Stop the taskStopTask();}/// <summary>/// Launch task in a new thread/// </summary>voidLaunchTaskAsync(){
taskToken =newCancellationTokenSource();Task.Factory.StartNew(()=>{try{//Capture the thread
runningTaskThread =Thread.CurrentThread;// Run the taskif(taskToken.IsCancellationRequested||!awaitReplyOnRequestEvent.WaitOne(10000))return;Console.WriteLine("Task finished!");}catch(Exception exc){// Handle exception}}, taskToken.Token);}/// <summary>/// Stop running task/// </summary>voidStopTask(){// Attempt to cancel the task politelyif(taskToken !=null){if(taskToken.IsCancellationRequested)return;else
taskToken.Cancel();}// Notify a waiting thread that an event has occurredif(awaitReplyOnRequestEvent !=null)
awaitReplyOnRequestEvent.Set();// If 1 sec later the task is still running, kill it cruellyif(runningTaskThread !=null){try{
runningTaskThread.Join(TimeSpan.FromSeconds(1));}catch(Exception ex){
runningTaskThread.Abort();}}}
Aufgaben bieten erstklassige Unterstützung für die Stornierung über Stornierungs-Token . Erstellen Sie Ihre Aufgaben mit Abbruchtoken und brechen Sie die Aufgaben über diese explizit ab.
Mit a können Sie CancellationTokensteuern, ob die Aufgabe abgebrochen wird. Sprechen Sie darüber, es abzubrechen, bevor es gestartet wird ("egal, ich habe das bereits getan") oder es tatsächlich in der Mitte zu unterbrechen? Wenn erstere, CancellationTokenkann das hilfreich sein; In letzterem Fall müssen Sie wahrscheinlich Ihren eigenen "Bail-out" -Mechanismus implementieren und an geeigneten Stellen in der Aufgabenausführung prüfen, ob Sie schnell fehlschlagen sollten (Sie können das CancellationToken weiterhin als Hilfe verwenden, es ist jedoch etwas manueller).
Aufgaben werden auf dem ThreadPool ausgeführt (zumindest wenn Sie die Standardfactory verwenden), sodass das Abbrechen des Threads keine Auswirkungen auf die Aufgaben haben kann. Für Aufgaben Abbruch findet Aufgabenabbruch auf msdn.
Ich habe es versucht, CancellationTokenSourceaber ich kann das nicht tun. Und das habe ich auf meine eigene Weise gemacht. Und es funktioniert.
namespace Blokick.Provider{publicclassSignalRConnectProvider{publicSignalRConnectProvider(){}publicboolIsStopRequested{get;set;}=false;//1-)This is important and default `false`.publicasyncTask<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;}}}
Und eine andere Klasse des Aufrufs der Methode:
namespace Blokick.Views{[XamlCompilation(XamlCompilationOptions.Compile)]publicpartialclassMessagePerson:ContentPage{SignalRConnectProvider signalR =newSignalRConnectProvider();publicMessagePerson(){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();}}}
Sie können eine Aufgabe wie ein roter Faden abbrechen , wenn die Aufgabe auf einem eigenen Thread erstellt dazu führen kann , und rufen Abortauf ihrenThread Objekt . Standardmäßig wird eine Aufgabe in einem Thread-Pool-Thread oder dem aufrufenden Thread ausgeführt, von denen Sie normalerweise keinen abbrechen möchten.
Erstellen Sie einen benutzerdefinierten Scheduler, von dem abgeleitet wird, um sicherzustellen, dass die Aufgabe einen eigenen Thread erhält TaskScheduler. QueueTaskErstellen Sie in Ihrer Implementierung von einen neuen Thread und verwenden Sie ihn zum Ausführen der Aufgabe. Später können Sie den Thread abbrechen, wodurch die Aufgabe in einem fehlerhaften Zustand mit a abgeschlossen wird ThreadAbortException.
Die Thread.AbortMethode sollte mit Vorsicht angewendet werden. Insbesondere wenn Sie es aufrufen, um einen anderen Thread als den aktuellen Thread abzubrechen, wissen Sie nicht, welcher Code ausgeführt wurde oder nicht ausgeführt werden konnte, wenn die ThreadAbortException ausgelöst wird, und Sie können sich auch nicht über den Status Ihrer Anwendung oder einen Anwendungs- und Benutzerstatus sicher sein dass es für die Erhaltung verantwortlich ist. Beispielsweise kann ein Aufruf Thread.Abortdie Ausführung statischer Konstruktoren verhindern oder die Freigabe nicht verwalteter Ressourcen verhindern.
Dieser Code schlägt mit einer Laufzeitausnahme fehl: System.InvalidOperationException: RunSynchronously kann möglicherweise nicht für eine bereits gestartete Task aufgerufen werden.
Theodor Zoulias
1
@ TheodorZoulias Guter Fang. Vielen Dank. Ich habe den Code korrigiert und die Antwort allgemein verbessert.
Edward Brey
1
Ja, das hat den Fehler behoben. Eine weitere Einschränkung, die wahrscheinlich erwähnt werden sollte, ist, dass Thread.Abortsie unter .NET Core nicht unterstützt wird. Der Versuch, es dort zu verwenden, führt zu einer Ausnahme: System.PlatformNotSupportedException: Thread-Abbruch wird auf dieser Plattform nicht unterstützt. Eine dritte Einschränkung ist, dass das SingleThreadTaskSchedulernicht effektiv mit Aufgaben im Versprechungsstil verwendet werden kann, dh mit Aufgaben, die mit asyncDelegierten erstellt wurden. Beispielsweise wird ein Embedded await Task.Delay(1000)in keinem Thread ausgeführt, sodass Thread-Ereignisse davon nicht betroffen sind.
Antworten:
Das kannst du nicht. Aufgaben verwenden Hintergrundthreads aus dem Threadpool. Das Abbrechen von Threads mit der Abort-Methode wird ebenfalls nicht empfohlen. Sie können sich den folgenden Blog-Beitrag ansehen, in dem erläutert wird, wie Aufgaben mithilfe von Stornierungs-Token ordnungsgemäß abgebrochen werden. Hier ist ein Beispiel:
quelle
Task.Wait(TimeSpan / int)
, ihm eine (zeitbasierte) Frist von außen zu geben.Task
? So etwas wie :public int StartNewTask(Action method)
. Innerhalb derStartNewTask
Methode erstelle ich eine neueTask
von :Task task = new Task(() => method()); task.Start();
. Wie kann ich das verwaltenCancellationToken
? Ich würde auch gerne wissen, obThread
ich eine Logik implementieren muss, um zu überprüfen, ob noch einige Aufgaben hängen, und sie dann zu töten, wennForm.Closing
. MitThreads
ich benutzeThread.Abort()
.Das Abbrechen einer Aufgabe ist problemlos möglich, wenn Sie den Thread erfassen, in dem die Aufgabe ausgeführt wird. Hier ein Beispielcode, um dies zu demonstrieren:
Ich habe Task.Run () verwendet, um den häufigsten Anwendungsfall dafür anzuzeigen - unter Verwendung des Komforts von Aufgaben mit altem Single-Threaded-Code, bei dem die CancellationTokenSource-Klasse nicht verwendet wird, um zu bestimmen, ob sie abgebrochen werden soll oder nicht.
quelle
CancellationToken
Unterstützung hat ...CancellationToken
oder noch einfachere Lösungen in Betracht gezogen werden, die frei von Rennbedingungen sind. Der obige Code veranschaulicht nur die Methode, nicht den Anwendungsbereich.thread
lokale Variable übergeben wird). In Ihrem Code wird der Hauptthread möglicherweise abgebrochen, was nicht wirklich gewünscht ist. Vielleicht wäre eine Überprüfung, ob die Threads vor dem Abbruch gleich sind, eine gute Idee, wenn Sie darauf bestehen, abzubrechenWie in diesem Beitrag vorgeschlagen , kann dies folgendermaßen erfolgen:
Obwohl es funktioniert, wird nicht empfohlen, einen solchen Ansatz zu verwenden. Wenn Sie den Code steuern können, der in der Aufgabe ausgeführt wird, sollten Sie die Stornierung ordnungsgemäß behandeln.
quelle
Diese Art von Dingen ist einer der logistischen Gründe, warum sie
Abort
veraltet sind. Verwenden SieThread.Abort()
in erster Linie nicht , um einen Thread abzubrechen oder zu stoppen, wenn dies überhaupt möglich ist.Abort()
sollte nur verwendet werden, um einen Thread gewaltsam zu beenden, der nicht auf friedlichere Anfragen reagiert, rechtzeitig anzuhalten.Davon abgesehen müssen Sie einen gemeinsamen Abbruchindikator bereitstellen, den ein Thread setzt und wartet, während der andere Thread regelmäßig prüft und ordnungsgemäß beendet. .NET 4 enthält eine speziell für diesen Zweck entwickelte Struktur, die
CancellationToken
.quelle
Sie sollten dies nicht direkt versuchen. Entwerfen Sie Ihre Aufgaben so, dass sie mit einem CancellationToken arbeiten , und brechen Sie sie auf diese Weise ab.
Außerdem würde ich empfehlen, Ihren Hauptthread so zu ändern, dass er auch über ein CancellationToken funktioniert. Anrufen
Thread.Abort()
ist eine schlechte Idee - es kann zu verschiedenen Problemen führen, die sehr schwer zu diagnostizieren sind. Stattdessen kann dieser Thread dieselbe Stornierung verwenden , die Ihre Aufgaben verwenden - und dieselbeCancellationTokenSource
kann verwendet werden, um die Stornierung aller Ihrer Aufgaben und Ihres Hauptthreads auszulösen .Dies führt zu einem weitaus einfacheren und sichereren Design.
quelle
Um die Frage von Prerak K zur Verwendung von CancellationTokens zu beantworten, wenn in Task.Factory.StartNew () keine anonyme Methode verwendet wird, übergeben Sie das CancellationToken als Parameter an die Methode, die Sie mit StartNew () beginnen, wie im MSDN-Beispiel gezeigt Hier .
z.B
quelle
Ich benutze einen gemischten Ansatz, um eine Aufgabe abzubrechen.
Kasse ein Beispiel unten:
quelle
Aufgaben bieten erstklassige Unterstützung für die Stornierung über Stornierungs-Token . Erstellen Sie Ihre Aufgaben mit Abbruchtoken und brechen Sie die Aufgaben über diese explizit ab.
quelle
Mit a können Sie
CancellationToken
steuern, ob die Aufgabe abgebrochen wird. Sprechen Sie darüber, es abzubrechen, bevor es gestartet wird ("egal, ich habe das bereits getan") oder es tatsächlich in der Mitte zu unterbrechen? Wenn erstere,CancellationToken
kann das hilfreich sein; In letzterem Fall müssen Sie wahrscheinlich Ihren eigenen "Bail-out" -Mechanismus implementieren und an geeigneten Stellen in der Aufgabenausführung prüfen, ob Sie schnell fehlschlagen sollten (Sie können das CancellationToken weiterhin als Hilfe verwenden, es ist jedoch etwas manueller).MSDN hat einen Artikel zum Abbrechen von Aufgaben: http://msdn.microsoft.com/en-us/library/dd997396.aspx
quelle
Aufgaben werden auf dem ThreadPool ausgeführt (zumindest wenn Sie die Standardfactory verwenden), sodass das Abbrechen des Threads keine Auswirkungen auf die Aufgaben haben kann. Für Aufgaben Abbruch findet Aufgabenabbruch auf msdn.
quelle
Ich habe es versucht,
CancellationTokenSource
aber ich kann das nicht tun. Und das habe ich auf meine eigene Weise gemacht. Und es funktioniert.Und eine andere Klasse des Aufrufs der Methode:
quelle
Sie können eine Aufgabe wie ein roter Faden abbrechen , wenn die Aufgabe auf einem eigenen Thread erstellt dazu führen kann , und rufen
Abort
auf ihrenThread
Objekt . Standardmäßig wird eine Aufgabe in einem Thread-Pool-Thread oder dem aufrufenden Thread ausgeführt, von denen Sie normalerweise keinen abbrechen möchten.Erstellen Sie einen benutzerdefinierten Scheduler, von dem abgeleitet wird, um sicherzustellen, dass die Aufgabe einen eigenen Thread erhält
TaskScheduler
.QueueTask
Erstellen Sie in Ihrer Implementierung von einen neuen Thread und verwenden Sie ihn zum Ausführen der Aufgabe. Später können Sie den Thread abbrechen, wodurch die Aufgabe in einem fehlerhaften Zustand mit a abgeschlossen wirdThreadAbortException
.Verwenden Sie diesen Taskplaner:
Beginnen Sie Ihre Aufgabe wie folgt:
Später können Sie abbrechen mit:
Beachten Sie, dass die Einschränkung zum Abbrechen eines Threads weiterhin gilt:
quelle
Thread.Abort
sie unter .NET Core nicht unterstützt wird. Der Versuch, es dort zu verwenden, führt zu einer Ausnahme: System.PlatformNotSupportedException: Thread-Abbruch wird auf dieser Plattform nicht unterstützt. Eine dritte Einschränkung ist, dass dasSingleThreadTaskScheduler
nicht effektiv mit Aufgaben im Versprechungsstil verwendet werden kann, dh mit Aufgaben, die mitasync
Delegierten erstellt wurden. Beispielsweise wird ein Embeddedawait Task.Delay(1000)
in keinem Thread ausgeführt, sodass Thread-Ereignisse davon nicht betroffen sind.