中止一个永远不会完成C#的方法的正确方法是什么?无线程中止



由于Thread.Abort方法不再受Microsoft支持。什么是通过从未(或在指定时间内(预期完成的操作的正确方法。我用Thread.Abort写的代码如下:

try
{
CancellationTokenSource cts = new CancellationTokenSource();                
Task t = Task.Run(() =>
{
TClass c1 = new TClass();
using (cts.Token.Register(Thread.CurrentThread.Abort))
{
c1.Generate();
}
}, cts.Token);
TimeSpan ts = TimeSpan.FromSeconds(5);
if (!t.Wait(ts))
{
cts.Cancel();                  
throw new Exception("Test success");
}
}
catch (Exception e)
{                
Console.WriteLine(e.Message);                             
}  
}

注意:c1.Generate()表示一个方法,如果它没有在特定时间内完成,我们希望中止它。

参考:https://learn.microsoft.com/en-us/dotnet/api/system.threading.thread.abort?view=net-6.0

编辑:

为TClass添加了代码[仅表示将永远运行的方法,现实世界中它是我们无法更改的第三方库方法]

public class TClass:IDisposable
{
public Thread Thread { get { return Thread.CurrentThread; } }
public TClass()
{
}
public void Dispose()
{
GC.SuppressFinalize(this);
}
public void Generate()
{
int x = 0;
while (true)
{
Console.WriteLine(x++);
Task.Delay(TimeSpan.FromSeconds(1)).Wait();
}
}
}

中止一个永远不会完成的不可取消方法的正确方法是在一个单独的进程上运行此方法,然后通过终止该进程来取消它。希望这个方法没有返回值,因为否则您将不得不通过进程间通信来获得这个值,这不是一件小事。

另一个不能保证有效的可能解决方案是使用Thread.Interrupt方法。只有当您知道方法运行的线程,并且该线程周期性(或永久性(转换为睡眠状态时,这才有效。有些操作,如异步方法,不是在线程上运行的,因此不能保证操作会终止,即使您通过中断来终止启动此操作的线程。

现在推荐的方法(特别是对于ASP.NET Core(是使用Tasks和"中止";他们使用CancellationTokens。您可以在这里了解更多关于如何使用CancellationTokens的信息。

您已经使用了CancellationTokenSource。使用其CancellationToken检查是否发出取消信号而不是中止。您试图中止的线程是一个线程池线程,它将由多个任务使用。

Generate应更改为:

public void Generate(CancellationToken token)
{
int x = 0;
while (token.IsCancellationRequested)
{
Console.WriteLine(x++);
Task.Delay(TimeSpan.FromSeconds(1)).Wait();
}
}

尽管这样的封锁不是一个好主意。这比Thread.Sleep好一点。方法应该是异步的:

public async Task Generate(CancellationToken token)
{
int x = 0;
while (token.IsCancellationRequested)
{
Console.WriteLine(x++);
await Task.Delay(TimeSpan.FromSeconds(1),token);
}
}

调用代码可以简化为:

var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1));                
await Task.Run(async ()=>{
var c1 = new TClass();
await c1.Generate(cts.Token);
},cts.Token);

如果你只想优雅地退出,并且等待延迟到期是可以的,你可以将代码更改为:

var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1));                
await Task.Run(async ()=>{
var c1 = new TClass();
await c1.Generate(cts.Token);
});

Generate到:

public async Task Generate(CancellationToken token)
{
int x = 0;
while (token.IsCancellationRequested)
{
Console.WriteLine(x++);
await Task.Delay(TimeSpan.FromSeconds(1));
}
}

相关内容

最新更新