gpt4 book ai didi

c# - 如何以线程安全的方式关闭表单(从后台线程使用)?

转载 作者:行者123 更新时间:2023-12-01 16:26:40 25 4
gpt4 key购买 nike

我有一个显示数据网格的表单。我还有一个在不同线程上运行的方法,该方法仅更新网格的显示单元格。为此,此方法调用表单上返回显示的单元格的函数。

我遇到的问题是,有时当表单已关闭并处置时,另一个线程上的方法仍在调用此函数,这会导致对象处置异常。有没有办法(除了确保另一个线程上的方法已完成)来防止这种情况?

所以我需要一个线程安全的方法来在表单关闭时终止后台任务。

private delegate List<foo> GetShownCellsDelegate();
public List<foo> GetShownCells()
{
if (this.InvokeRequired)
{
GetShownCellsDelegate getShownCellsDelegate = new GetShownCellsDelegate(GetShownCells);
return (List<foo>)this.Invoke(getShownCellsDelegate);
}
else
{
//do stuff
}
}

我尝试使用表单的 IsDispose 属性:

if (!IsDisposed)
{
return (List<foo>)this.Invoke(getShownCellsDelegate);
}

但显然该表单可以在 if 语句之后被丢弃,因为我仍然收到 isdispose 异常。

这是我在另一个线程上使用该函数的方式:

private CancellationTokenSource cts = new CancellationTokenSource();
public void CancelUpdate()
{
cts.Cancel();
}

public void ReadDataFromDevice()
{
ThreadPool.QueueUserWorkItem(new WaitCallback(ReadAllDataThreadPoolMethod));
}

private void ReadAllDataThreadPoolMethod(Object stateInfo)
{
if (!cts.IsCancellationRequested)
{
//do stuff
}
}

CancelUpdate 方法是从表单上的 IsClosing 事件调用的。但有时我仍然会遇到 isdispose 异常。

最佳答案

要取消长时间运行的操作,您可以使用 CancellationToken,它是专为协作取消而设计的。

让主窗体在启动后台线程时创建一个 CancellationTokenSource,将 CTS 生成的 CacellationToken 传递给后台线程,在窗体关闭时取消 CTS,然后让后台线程检查 token 以查看它是否在尝试调用回主线程之前被取消。

public void Foo()
{
var cts = new CancellationTokenSource();
var task = Task.Run(() => DoWork(cts.Token));
FormClosing += (s, args) =>
{
cts.Cancel();
if (!task.IsCompleted)
{
args.Cancel = true;
task.ContinueWith(t => Close());
}
};
}
private void DoWork(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
//Do some work
}
}

要绝对确保后台线程没有通过取消检查,然后屈服于 UI 线程以使其取消 token 并处置表单,在工作完成之前,您还需要确保后台线程在取消后、表单关闭之前有时间运行完成。这可以通过关闭处理程序中的简单 Thread.Join 调用来完成。

关于c# - 如何以线程安全的方式关闭表单(从后台线程使用)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23809740/

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