簡體   English   中英

處理后完成一個線程循環

[英]Finishing up a thread loop after disposal

我正在尋找C#中的線程安全代碼,如果可能的話,將避免兩個問題;

  1. 如果線程對象在任何點被丟棄,則線程循環很好地退出。
  2. 當由另一個類或表單(特別是表單)使用時,使用該類的開發人員不必記住掛鈎表單的close事件並調用dispose。 例如, 正確完成服務器線程

線程正在調用一個具有以下while循環的方法;

while (!Finished)
{
    string request = "";
    try
    {
        //Block until we have a message or we are terminated in dispose **
        request = server.Recv(Encoding.Unicode);  
        //Send a response to the sender so they know we received. 
        server.Send(request, Encoding.Unicode);
    }
    catch (Exception e)
    {
        //Catch a termination error. 
        if (e.Errno == ETERM)
        {
            break;
        }
    }
    syncContext.Post(
                     new SendOrPostCallback(delegate(object state)
                     {
                         MessageHandler handler = OnMessage;
                         if (handler != null)
                         {
                             handler(request);
                         }
                     }), null);
}

處置目前看起來像這樣;

public void Dispose()
{
    Finished = true;
    //Cause all blocking message requests and sends to terminate with exception ** 
    FZMQConext.Dispose();

    //Wait for the thread to finish up.
    FThread.Join();
    GC.SuppressFinalize(this);
}

我認為的問題是;

  • 我的事件可以被調用,即使我正在處理我的類,因為線程必須完成推出。 在try / catch和syncContext.Post()之間調用dispos。 這有多糟糕?
  • 有沒有辦法結束這個類,所以它的用戶不必記得調用dispose。 目前,如果他們沒有應用程序坐在那里等待線程完成,它永遠不會。 將它設置為后台線程似乎很懶惰。

我的事件可以被調用,即使我正在處理我的類,因為線程必須完成推出。 在try / catch和syncContext.Post()之間調用dispos。 這有多糟糕?

它看起來並不那么糟糕。 一旦你設置Finished=true 它應該完成發布一個新的委托,然后退出循環。 但是,您可能會遇到Finished CPU緩存問題。 運行循環的CPU核心可以另一個線程更改了值讀取Finished緩存值,因此循環可能會錯誤地繼續運行。 要防止這種情況,您應該創建一個僅通過Interlocked修改的私有字段,以及一個修改該字段的方法:

private int _running = 1;
public void Stop()
{
    Interlocked.Exchange(ref _running, 0);
}

並且循環將while( _running > 0)

有沒有辦法結束這個類,所以它的用戶不必記得調用dispose。 目前,如果他們沒有應用程序坐在那里等待線程完成,它永遠不會。 將它設置為后台線程似乎很懶惰。

實際上沒有一般方法可以避免將處置負擔放在客戶身上。 但是如果這個類總是被Winforms組件使用,那么你可以編寫一個構造函數來獲取父組件並訂閱父組件的Disposed事件。 因此,當處理父組件(例如表單)時,此對象也會被處置:

public MyClass(Component parent)
{
    parent.Disposed += (s,e) => this.Dispose();
}

(我會把終結器作為一個選項扔出去,因為無法確定是否/什么時候會運行。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM