2011-02-17 192 views
5

我有一個線程出去查找我們的(舊)SQL服務器上的數據。如何殺死一個C#線程?

隨着數據的進入,我發佈信息到一個模式對話框 - 用戶不能做任何事情,而所有這些處理都在進行。模態對話框只是爲了讓他們看到我正在做一些事情,並阻止他們同時運行另一個查詢。

有時(很少),當代碼調用SQL服務器時,服務器不響應(IT維護人員維護它,LAN線路被切斷或PC不在網絡中)或者做查詢的人用完了時間。所以,模式對話框確實有一個取消按鈕。

線程對象(System.Threading.Thread)具有IsBackground=true

當用戶點擊取消,我打電話給我的KillThread方法。

注意:我不能在該類中使用BackgroundWorker組件,因爲它與一些Windows Mobile 5代碼共享& WM5沒有BackgroundWorker。

void KillThread(Thread th) { 
    if (th != null) { 
    ManualResetEvent mre = new ManualResetEvent(false); 
    Thread thread1 = new Thread(
    () => 
     { 
     try { 
      if (th.IsAlive) { 
      //th.Stop(); 
      // 'System.Threading.Thread' does not contain a definition for 'Stop' 
      // and no extension method 'Stop' accepting a first argument of type 
      // 'System.Threading.Thread' could be found (are you missing a using 
      // directive or an assembly reference?) 
      th.Abort(); 
      } 
     } catch (Exception err) { 
      Console.WriteLine(err); 
     } finally { 
      mre.Set(); 
     } 
     } 
    ); 
    string text = "Thread Killer"; 
    thread1.IsBackground = true; 
    thread1.Name = text; 
    thread1.Start(); 
    bool worked = mre.WaitOne(1000); 
    if (!worked) { 
     Console.WriteLine(text + " Failed"); 
    } 
    th = null; 
    } 
} 

在我的輸出窗口,我總是看到「主題殺手失敗」,但沒有異常丟進。

我應該如何停止一個線程?

最好相關的帖子,我發現其中兩個以下:

How to Kill Thread in C#?
How to kill a thread instantly in C#?

編輯:

似乎有一些混亂與方法我列在上面。

首先,當有人點擊取消按鈕,這個程序被調用:

void Cancel_Click(object sender, EventArgs e) { 
    KillThread(myThread); 
} 

接下來,當我去殺死一個線程,我寧願沒有永遠等待線程停止。同時,如果線程仍處於活動狀態,我不想讓代碼繼續。所以,我使用了一個ManualResetEvent對象。它不應該需要一整秒(1000毫秒)只是爲了停止線程,但每次WaitOne方法超時。

還在聽的想法。

回答

7

簡答:你沒有。通常你通過發信號表示你想退出。 如果您正在觸發SQL查詢,請異步執行(請原諒我的拼寫),並在必要時取消它。這真的適用於單獨的線程中的任何冗長的任務。

進一步的閱讀可見埃裏克利珀的文章: Careful with that axe, part one: Should I specify a timeout?Careful with that axe, part two: What about exceptions?

編輯: 你怎麼稱呼的SQL Server? ADO,TDS,標準/定製庫等...? 該呼叫應該作爲異步。 因此:StartOpeningConnection,WaitFor OpeningComplete,StartQuery,WaitFor QueryComplete,Start CloseConnection,WaitFor CloseConnectionComplete等。在等待線程應該休眠的任何時候。在喚醒之後,檢查你的父線程(UI線程)是否已經取消,或者發生了超時並退出線程並可能通知sqlserver你已完成(關閉連接)。

這並不容易,但很少是...

編輯2:在你的情況,如果你無法改變數據庫代碼asynchrone,使它成爲一個獨立的進程,殺掉,如果neccesary 。這樣資源(連接等)將被釋放。使用線程,情況並非如此。 但這是一個醜陋的破解

編輯3: 您應該使用BeginExecuteReader/EndExecuteReader模式。 this article is a good reference: 這將需要重寫您的數據訪問代碼,但這是正確的做法。

0

當用戶點擊取消,您應該發出信號的事件(不能殺死線程)。在你的例子中,ManualResetEvent的「mre」的作用域應該在線程函數之外。

+0

我要編輯我的帖子。我想我已經寫錯了。 – jp2code 2011-02-17 21:21:15

+0

這裏的觀點(和MarcelDevG指出的一樣)是你不要殺死一個線程。線程應該優雅地退出並自行清理。 – 2011-02-17 21:45:50

+0

這將是一個想法。但是,我無法告訴我們的SQL Server 2000停止查詢。我想我可以簡單地放棄線程(將其設置爲NULL,然後在執行下一個查詢時創建一個新實例),但我想知道如何停止線程。 – jp2code 2011-02-17 22:06:56

2

給我的感覺是,同時螺紋1000毫秒中止是不夠的。 MSDN建議您調用Thread.Join。看到正在中止的代碼肯定會有所幫助。

Thread.Abort

線程不能保證立即中止 ,或在所有。 如果一個線程執行 無限量的計算,則會發生這種情況 終止塊被終止程序的部分 調用,因此 無限期地延遲中止。到 等到一個線程中止後, 可以在調用Abort方法後調用線程 上的Join方法,但 不能保證等待將會以 結束。

+0

好吧,它有很多自定義設計的對象被填充在查詢中。查詢輪詢6個不同的數據表(我沒有設計系統,我只是爲它編寫軟件)。在查詢每個表之前,我檢查線程是否被中止。比賽條件,也許,但這就是我所擁有的。 – jp2code 2011-02-17 21:19:06

1

你傳遞給你的KillThread方法是什麼?取消按鈕將在UI線程上被點擊,而不是你想要殺死的那個。