2014-05-22 41 views
2

我有一个表格显示数据网格。我也有一个方法在不同的线程上运行,只更新网格中显示的单元格。为此,此方法在返回显示的单元格的窗体上调用一个函数。如何以线程安全的方式关闭表单(用于后台线程)?

我遇到的问题是,有时在表单被关闭和处置的情况下,另一个线程上的方法仍在调用这个函数,这会导致对象抛出的异常。有没有一种方法(其他则确保另一个线程的方法已完成)来防止这种情况发生?

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

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 
    } 
} 

我尝试用表格的IsDisposed属性:

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

但显然形式可以if语句后dispossed因为我仍然得到isdisposed例外。

这是我如何使用其他线程的功能:

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事件被调用。但我仍然有时会遇到遗漏的异常。

回答

5

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

具备的主要形式创建CancellationTokenSource启动后台线程时,路过的CTS产生的底色线程CacellationToken,取消CTS当你的窗体关闭,然后让后台线程检查标志,看它是否在尝试返回主线程之前被取消。

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线程拥有它取消令牌和处置形式,工作完成之前,你会还需要确保后台线程有时间在被取消之后运行到完成之后,在表单关闭之前。这可以通过关闭处理程序中的一个简单的Thread.Join调用完成。

+0

我编辑了我的问题以显示我是如何使用它的。有时我仍然会遇到异常情况。 –

+0

@ Marc.O完全正确。我想,这应该是一场艰难的比赛条件,但它确实存在。请参阅编辑。 – Servy

+0

但是,然后你阻塞线程,直到UI线程完成?我不认为这会发生,直到你关闭整个程序? –

0
this.FormClosed += new FormClosedEventHandler(form1_FormClosed); 
void form1_FormClosed(object sender, FormClosedEventArgs e) 
{ 
    //close thread 
} 

这将在您的表单关闭时执行。

+0

尽管如此,但这并不能解释如何将相关信息传递给后台线程。 – user2864740

+0

你会如何处理这件事? –