2014-05-22 40 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

你會如何處理這件事? –