gpt4 book ai didi

c# - 如果线程花费太长时间,如何停止线程

转载 作者:行者123 更新时间:2023-12-03 19:34:46 25 4
gpt4 key购买 nike

我遇到一种情况,我将数据导出到文件,我被要求做的是提供一个取消按钮,如果导出时间过长,单击该按钮将停止导出。

我开始在线程中导出到文件。我尝试在单击按钮时中止线程。但这不起作用。

我在Google上搜索了一下,发现不推荐使用abort()。但我还应该选择什么来实现它?

我当前的代码是:

private void ExportButtonClick(object param)
{
IList<Ur1R2_Time_Points> data = ct.T_UR.ToList();
DataTable dtData = ExportHelper.ToDataTable(data);
thread = new Thread(new ThreadStart(()=>ExportHelper.DataTableToCsv(dtData, "ExportFile.csv")));
thread.SetApartmentState(ApartmentState.STA);
thread.IsBackground = true;
thread.Name = "PDF";
thread.Start();
}

private void StopButtonClick(object param)
{
if (thread.Name == "PDF")
{
thread.Interrupt();
thread.Abort();
}
}

最佳答案

中止线程是一个坏主意,尤其是在处理文件时。您将没有机会清理半写入的文件或清理不一致的状态。

它不会损害 .NET 运行时,但它可能会损害您自己的应用程序,例如,如果辅助方法使全局状态、文件或数据库记录处于不一致的状态。

最好使用协作取消 - 线程定期检查协调构造,如 ManualResetEventCancellationToken 。您不能使用像 bool 标志这样的简单变量,因为这可能会导致竞争条件,例如,如果两个或多个线程尝试同时设置它。

您可以在 Cancellation in Managed Threads 中阅读有关 .NET 中的取消的信息。 MSDN 部分。

.NET 4 中添加了 CancellationToken/CancellationTokenSource 类,以使取消比传递事件更容易。

就您而言,您应该修改您的 DataTableToCsv 以接受 CancellationToken 。该 token 是由 CancellationTokenSource 生成的类(class)。

当您调用CancellationTokenSource.Cancel时 token 的 IsCancellationRequested属性变为真。您的 DataTableToCsv 方法应定期检查此标志。如果设置了,它应该退出任何循环,删除任何不一致的文件等。

CancelAfter 直接支持超时。本质上,CancelAfter 启动一个计时器,当计时器到期时将触发 Cancel

您的代码可能如下所示:

CancellationTokenSource _exportCts = null;

private void ExportButtonClick(object param)
{
IList<Ur1R2_Time_Points> data = ct.T_UR.ToList();
DataTable dtData = ExportHelper.ToDataTable(data);

_exportCts=new CancellationTokenSource();
var token=_exportCts.Token;

thread = new Thread(new ThreadStart(()=>
ExportHelper.DataTableToCsv(dtData, "ExportFile.csv",token)));
thread.SetApartmentState(ApartmentState.STA);
thread.IsBackground = true;
thread.Name = "PDF";

_exportCts.CancelAfter(10000);
thread.Start();

}


private void StopButtonClick(object param)
{
if (_exportCts!=null)
{
_exportCts.Cancel();
}
}

DataTableToCsv 应包含与此类似的代码:

foreach(var row in myTable)
{
if (token.IsCancellationRequested)
{
break;
}
//else continue with processing
var line=String.Join(",", row.ItemArray);
writer.WriteLine(line);

}

通过使用任务而不是原始线程,您可以相当多地清理代码:

private async void ExportButtonClick(object param)
{
IList<Ur1R2_Time_Points> data = ct.T_UR.ToList();
DataTable dtData = ExportHelper.ToDataTable(data);

_exportCts=new CancellationTokenSource();
var token=_exportCts.Token;

_exportCts.CancelAfter(10000);
await Task.Run(()=> ExportHelper.DataTableToCsv(dtData, "ExportFile.csv",token)));
MessageBox.Show("Finished");
}

您还可以通过使用异步操作来加快速度,例如从数据库读取数据或写入文本文件,无需阻塞或使用线程。 Windows IO(文件和网络)在驱动程序级别是异步的。类似 File.WriteLineAsync 的方法不要使用线程写入文件。

您的导出按钮处理程序可能会变成:

private void ExportButtonClick(object param)
{
IList<Ur1R2_Time_Points> data = ct.T_UR.ToList();
DataTable dtData = ExportHelper.ToDataTable(data);

_exportCts=new CancellationTokenSource();
var token=_exportCts.Token;

_exportCts.CancelAfter(10000);
await Task.Run(async ()=> ExportHelper.DataTableToCsv(dtData, "ExportFile.csv",token)));
MessageBox.Show("Finished");
}

DataTableToCsv:

public async Task DataTableToCsv(DataTable table, string file,CancellationToken token)
{
...
foreach(var row in myTable)
{
if (token.IsCancellationRequested)
{
break;
}
//else continue with processing
var line=String.Join(",", row.ItemArray);
await writer.WriteLineAsync(line);
}

关于c# - 如果线程花费太长时间,如何停止线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42268735/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com