C # İş Parçacığı Sonlandırma ve Thread.Abort ()


85

MSDN'de, Thread.Abort () yönteminin açıklaması şöyle diyor: "Bu yöntemi çağırmak genellikle iş parçacığını sonlandırır."

Neden HER ZAMAN olmasın?

Hangi durumlarda iş parçacığını sonlandırmaz?

Konuları sonlandırmanın başka bir yolu var mı?

Yanıtlar:


60

Thread.Abort()ThreadAbortExceptioniş parçacığına bir enjekte eder . İş parçacığı arayarak isteği iptal edebilir Thread.ResetAbort(). Ayrıca, finallyistisna ele alınmadan önce çalıştırılacak blok gibi belirli kod parçaları vardır . Herhangi bir nedenden dolayı iş parçacığı böyle bir blokta sıkışmışsa, iş parçacığında istisna asla ortaya çıkmayacaktır.

Arayan kişi arama sırasında iş parçacığının durumu üzerinde çok az kontrole sahip olduğundan Abort(), genellikle bunu yapması tavsiye edilmez. Bunun yerine iş parçacığına sonlandırma isteyen bir mesaj iletin.


Ne tür bir mesaj? Bir yöntem çağrısı mı demek istiyorsun?
user101375

4
Bu, iş parçacıklarınız arasında nasıl veri ilettiğinize bağlıdır. Örneğin, iş parçacığınız bir görev kuyruğu olan bir çalışan iş parçacığı ise, bir PleaseTerminate iletisini sıraya koyabilir ve iş parçacığının onu düzgün bir şekilde işlemesine izin verebilirsiniz.
Brian Rasmussen

İş parçacığımın çözülmesi gereken büyük bir sorunu var, görev sırası yok.
user101375

Dediğim gibi, iş parçacığı kodunuzun nasıl tasarlandığına bağlı. Belki o zaman bir üye değişkeni aracılığıyla sinyal gönderebilirsiniz. Mevcut kod olmadan daha spesifik olmak zordur.
Brian Rasmussen

54

Hangi durumlarda iş parçacığını sonlandırmaz?

Bu soru bir kopya.

Thread.Abort () kullanmanın nesi yanlış?

Konuları sonlandırmak için başka bir olasılık var mı?

Evet. Senin sorunun şu ki, kibarca durmasını söyleyemeyeceğin bir iş parçacığı asla başlatmamalısın ve zamanında dur. (1) Durdurması zor, (2) hatalı veya en kötüsü (3) kullanıcıya düşman olabilecek bir ileti dizisi başlatmanız gereken bir durumdaysanız, yapılacak doğru şey yapmaktır. yeni bir işlem, iş parçacığını yeni işlemde başlatın ve ardından iş parçacığının aşağı inmesini istediğinizde işlemi sonlandırın . İşbirliği yapmayan bir iş parçacığının güvenli bir şekilde sonlandırılmasını garanti edebilecek tek şey, işletim sisteminin tüm sürecini kaldırmasıdır.

Daha fazla ayrıntı için bu soruya verdiğim aşırı uzun cevabıma bakın:

C # 'da bir döngü içinde kilit ifadesini kullanma

İlgili kısım, sonlandırmadan önce bir iş parçacığının kendisini öldürmesi için ne kadar beklemeniz gerektiğine dair düşüncelerin neler olduğunu tartıştığım son kısımdır.


Eric, bu iş parçacığı bir eşitleme nesnesini bekliyorsa, bir iş parçacığına kibarca durmasını nasıl söyleyebilirim, örneğin EventWaitHandle.WaitOne () ;?
Corvin

5
@Corvin: Bir iş parçacığının diğeriyle nasıl iletişim kuracağını açıklayan iki iş parçacığı arasındaki sözleşme, bu iş parçacıkları üzerinde çalışan kodun yazarlarına bağlıdır. (1) X iş parçacığının potansiyel olarak sonsuza kadar bir nesne üzerinde beklemesi ve (2) bu Y iş parçacığının X iş parçacığını sınırlı bir süre içinde temiz bir şekilde kapatabilmesi için gereksinimleriniz varsa, o zaman çelişkili gereksinimleriniz olduğunu düşünüyorum; hangisinin kazanacağına karar verin. İlki ise, iş parçacığı Y beklemek zorunda kalacak. İkincisi, o zaman X iş parçacığı sonsuza kadar beklememeli, biraz zaman beklemelidir.
Eric Lippert

Cevabın için teşekkür ederim. Aşağıdaki mimariyi düşünün: Sistem genelinde belirli bir olay meydana geldiğinde kendini küçültmesi gereken bir uygulamam var. Bu uygulamada, genel adlandırılmış bir olayı bekleyen ve bu olay ayarlandığında işini yapan bir iş parçacığım var. Öte yandan, uygulamamın olay gerçekleşmeden önce beklemedeki iş parçacığını kapatmak zorunda kalmadan çıkması gerekebilir. Böyle bir şeyi kodlamanın samuray yolu nedir?
Corvin

@Corvin: Olay için bekleyen (kısa bir zaman aşımıyla) bir döngüye sahip olabilirsiniz, ardından beklemeyi bırakıp bırakmayacağını kontrol eder (böylece normal şekilde çıkabilir). Bu şekilde, iş parçacığınıza durması gerektiğini bildirebilirsiniz ve yalnızca durması için zaman aşımınız olduğu sürece beklemeniz gerekir.
Kevin Kibler

2
@Corvin, bu bekleme iş parçacığını bir arka plan iş parçacığı yaparsanız, uygulamadan çıkmadan önce kapatmanız gerekmez.
Don Kirkby

17

Neden HER ZAMAN olmasın? Hangi durumlarda ipliği sonlandırmaz?

Yeni başlayanlar için, bir iş parçacığı a'yı yakalayabilir ThreadAbortExceptionve kendi sonlandırmasını iptal edebilir . Ya da siz onu durdurmaya çalışırken sonsuza kadar sürecek bir hesaplama yapabilir. Bu nedenle, çalışma zamanı, siz sorduktan sonra iş parçacığının her zaman sona ereceğini garanti edemez.

ThreadAbortException daha fazla var:

Bir iş parçacığını yok etmek için Abort yöntemine bir çağrı yapıldığında, ortak dil çalışma zamanı bir ThreadAbortExceptionoluşturur. ThreadAbortException, yakalanabilen özel bir istisnadır, ancak catch bloğunun sonunda otomatik olarak yeniden yükseltilecektir. Bu istisna ortaya çıktığında, çalışma zamanı evreyi sonlandırmadan önce tüm son blokları yürütür. İş parçacığı, son bloklarda sınırsız bir hesaplama yapabildiğinden veya Thread.ResetAbort()iptali iptal etmek için çağrı yapabildiğinden , iş parçacığının biteceğine dair hiçbir garanti yoktur.

Abort()Manuel olarak bir iş parçacığı oluşturmanıza gerek yoktur . Basitçe iş parçacığındaki yöntemin geri dönmesine izin verirseniz, CLR sizin için tüm kirli işleri yapacaktır; bu iş parçacığı normal şekilde sonlandıracaktır.


Bu iş parçacığında (Dispatcher.Run ();) başlatılan bir mesaj döngüsü nedeniyle onu Abort () yapmam gerekiyor. Doğru anlarsam, bitirmek için iş parçacığına dönüş çağrısı yapan bir yöntemi çağırmam gerekir mi?
user101375

7

FileStream.Read()şu anda hiçbir şey almayan adlandırılmış bir boruya (gelen verileri beklerken arama bloklarını oku) yanıt vermeyecektir Thread.Abort(). Read()Aramanın içinde kalır .


6

Ya iş parçacığı bir kilit tutuyorsa ve durdurulursa / öldürülürse? Kaynaklar sıkışmış durumda

Bir iş parçacığı kendini iptal çağırdığında ancak başka bir iş parçacığı tarafından olmadığında iyi çalışır. İptal, görevini tamamlamamış olsa bile etkilenen iş parçacığını zorla sonlandırır ve kaynakların temizlenmesi için hiçbir fırsat sağlamaz

MSDN'ye başvur


bkz: Yönetilen İş Parçacığı Oluşturma En İyi Uygulamaları


5

Bir döngüde sıkışmış bir iş parçacığını iptal edemiyorum:

//immortal
Thread th1 = new Thread(() => { while (true) {}});

Bununla birlikte, döngü sırasında uyursa iş parçacığını iptal edebilirim:

//mortal
Thread th2 = new Thread(() => { while (true) { Thread.Sleep(1000); }});

1
bu doğru görünmüyor, bir test programı çalıştırdım: `{var th = new Thread (() => {int i = 0; try {while (true) {i ++;}} catch (Exception e) { Console.WriteLine ("aborting @ {0}", i);}}); th.Start (); Thread.Sleep (1000); th.Abort (); th.Join (); }
Weipeng L


3

Çünkü işleyiciyi yakalayabilir ThreadAbortExceptionve Thread.ResetAbortiçini arayabilirsiniz .


0

OT: Kapsamlı, dilden bağımsız, şüpheli derecede yararlı ve cüretkar komik eşzamanlılık değerlendirmesi için bkz Verity Stob !


-1

İş parçacığının Abort () çağrısını duymak için çok meşgul olduğu durumlar yaşadım, bu genellikle koduma bir ThreadAbortingException atılmasına neden oluyor.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.