在线程中,我创建了一些线程System.Threading.Task
并启动了每个任务。
当我执行.Abort()
杀死线程的操作时,任务不会中止。
如何将传递.Abort()
给我的任务?
在线程中,我创建了一些线程System.Threading.Task
并启动了每个任务。
当我执行.Abort()
杀死线程的操作时,任务不会中止。
如何将传递.Abort()
给我的任务?
Answers:
你不能 任务使用线程池中的后台线程。另外,也不建议使用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()
是一个坏主意-它可能导致各种问题,这些问题很难诊断。相反,该线程可以使用您的任务使用的相同的Cancellation(取消),并且该线程可以CancellationTokenSource
用于触发所有任务和主线程的取消。
这将导致更简单,更安全的设计。
要回答Prerak K关于在Task.Factory.StartNew()中不使用匿名方法时如何使用CancellationTokens的问题,您可以将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/zh-cn/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)
在无线程中运行,因此它不受线程事件的影响。