2015-07-10 42 views
4

我有這樣的代碼如何停止一個線程在其他結束

 Thread thread1 = new Thread(this.DoSomething1); 
     Thread thread2 = new Thread(this.DoSomething2); 
     thread1.Start(); 
     thread2.Start(); 

我需要完成立刻殺死對方的第一個線程。 請注意,該線程不是那種運行一段時間的樣子,所以我不能使用一個靜態變量來告訴線程停止。哪個線程會先結束?

+2

有沒有安全的方法殺死一個線程。至於等待其中一個任務完成,只需使用'Task.Run'而不是創建手動線程,並且可以使用'Task.WhenAny'。 – Luaan

+1

這聽起來有點[XY問題](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)。你的線索究竟在做什麼,你需要他們以這種方式行事? –

+0

夥計們,感謝您的快速響應,但: 1.我的線程不會循環。 2.他們完成不同的工作。 – user3671974

回答

0

你在這些線程中做什麼非常重要。如果在兩者中都有for循環,則可以通過讀取循環開始或循環體中任何位置的共享變量來停止線程。如果它只是沉重的計算(複雜的業務流程或複雜的數學事物),那麼在某件事情中殺死一個線程甚至是危險的。

+0

殺死一個線程是_always_危險的。它應該始終通過響應同步原語而協作退出。 – xxbbcc

4

理想情況下,您希望使用取消令牌或靜態變量來安全地取消線程。


如果你決定使用的CancellationToken/tokenSource:

var tokenSource = new CancellationTokenSource(); 
    var token = tokenSource.Token; 

    ... 

    static void DoSomething1or2(CancellationToken token, CancellationTokenSource tokenSource) 
    { 

     //Do other work here 

     //Since you said neither of your tasks were looping, just put this where 
     //you'd want to cancel the thread 
     if(token.IsCancellationRequested) 
     return; // or token.ThrowIfCancellationRequested(); 

     //do some more stuff here 

     tokenSource.IsCancellationRequested = true; 
    } 

如果您DoSomething的方法循環,​​那麼你可以在開始或每次循環結束時檢查一個布爾值,看看是否另一個線程完成。這種技術與cancellationToken非常相似。

if(otherThreadIsActive && originalCondition) 
    { 
     //do stuff here 
    } 

如果你不能等待迭代完成,否則無法使用取消標記,那麼我建議你閱讀this thread on aborting。最好不要使用它,除非它是絕對必要的。


最好的辦法:使用取消標記/ tokenSource

下一個最好的方法:使用某種布爾來決定何時終止

+0

這是 - 大部分 - 要走的路。你應該刪除中止部分,不是因爲它在技術上是錯誤的,而是因爲這對於OP發佈的(相當平凡的)例子是不正確的。我沒有看到OP的代碼中有任何例外情況會保證中止另一個線程(你怎麼知道哪個線程會被中止 - 一個甚至不知道哪個線程會先啓動,並且不能保證當你發出時會發生中止命令)。如果您刪除了中止部分,我會加快解決您的問題。 – xxbbcc

+0

@xxbbcc我會強調他真的不應該使用thread.Abort(),但我不想刪除它。更好的人知道它,而不是使用它,而不是無知。 – Speerian

+0

我同意你的詳細說明,所以+1 – xxbbcc

1

Thread是「射後不理」你開始並且再也不會互動的任務。如果您需要與線程交互,例如在線程啓動後停止線程,或者需要知道線程何時完成,則應使用Task.Run而不是Thread。如果您想在任務仍在運行時取消任務,則需要CancellationTokenSource

var cts = new [] { 
    new CancellationTokenSource(), 
    new CancellationTokenSource()}; 
var ts = new[] 
{ 
    Task.Run(() => DoSomething1(cts[0].Token), cts[0].Token), 
    Task.Run(() => DoSomething2(cts[1].Token), cts[1].Token) 
}; 

var w = Task.WaitAny(ts); 
for (int i = 0; i < cts.Length; i++) 
{ 
    if (i != w) cts[i].Cancel(); 
} 

DoSomething旨意必須監控CancellationToken.IsCancellationRequested取消並執行清理。您需要將令牌傳遞給Task.Run以檢測線程是否引發異常,但我沒有說明。欲瞭解更多信息,請諮詢How to Cancel a Task and Its Children

0

我在過去處理同步線程取消時所做的工作是在類中有一個靜態事件來激活線程。這些線程執行所有監聽這個靜態事件的不同類的函數。當這個事件觸發時,volatile private bool _aboutRequested被設置爲真,這是在啓動線程執行類中找到的。在線程執行循環中,最後一件事是檢查此退出請求的布爾值,如果爲true,則優雅地退出。

相關問題