.NET'te zombiler var mı?


385

.NET'te kilitleme hakkında bir takım arkadaşıyla bir tartışma yapıyordum. Hem alt düzey hem de üst düzey programlamada geniş bir geçmişi olan gerçekten parlak bir adam, ancak daha düşük düzeyli programlama ile olan deneyimi benimkini aşıyor. Her neyse, O, bir sistemin çökmesine "zombi iplik" olasılığını önlemek için mümkün olduğunca ağır yük altında olması beklenen kritik sistemlerde .NET kilitlemeden kaçınılması gerektiğini savundu. Ben rutin kilitleme kullanın ve bir "zombi iplik" ne olduğunu bilmiyordum, bu yüzden sordum. Onun açıklamasından edindiğim izlenim, bir zombi iş parçacığının sonlandırılmış ancak bir şekilde hala bazı kaynaklara tutunan bir iş parçacığı olduğudur. Bir zombi iş parçacığının bir sistemi nasıl kırabileceğine dair bir örnek, bir iş parçacığının bir nesneye kilitlendikten sonra bazı prosedürlere başlamasıydı, ve sonra kilit açılmadan önce bir noktada sonlandırılır. Kilitli nesneyi kullanan iş parçacığı öldüğünden, sonunda, bu yöntemi yürütme girişimleri iş parçacıklarının hiçbir zaman döndürülmeyecek bir nesneye erişim için beklemesine neden olacağından, bu durum sistemin çökme potansiyeline sahiptir.

Sanırım bunun özünü aldım, ama eğer üssüm yoksa lütfen bana bildirin. Kavram bana mantıklı geldi. Bunun .NET'te gerçekleşebilecek gerçek bir senaryo olduğuna tamamen ikna olmadım. Daha önce hiç "zombileri" duymadım, ancak daha düşük seviyelerde derinlemesine çalışan programcıların, bilgisayarla ilgili temel bilgileri (iş parçacığı gibi) daha derin bir şekilde anlama eğiliminde olduklarını kabul ediyorum. Bununla birlikte, kesinlikle kilitlemenin değerini görüyorum ve birçok birinci sınıf programcının kilitlemeden yararlandığını gördüm. Ben de bunu kendim için değerlendirmek için sınırlı yeteneğim var, çünkü lock(obj)ifadenin gerçekten sadece sözdizimsel şeker olduğunu biliyorum :

bool lockWasTaken = false;
var temp = obj;
try { Monitor.Enter(temp, ref lockWasTaken); { body } }
finally { if (lockWasTaken) Monitor.Exit(temp); }

ve çünkü Monitor.Enterve Monitor.Exitişaretlidir extern. .NET'in, iş parçacıklarını bu tür bir etkiye sahip olabilecek sistem bileşenlerine maruz kalmaya karşı koruyan bir tür işlem gerçekleştirdiği düşünülebilir, ancak bu tamamen spekülatif ve muhtemelen sadece "zombi konuları" daha önce hiç duymadığım gerçeğe dayanıyor önce. Bu yüzden, bu konuda bazı geri bildirimler alabileceğimi umuyorum:

  1. "Zombi parçacığının" burada açıkladığımdan daha net bir tanımı var mı?
  2. .NET'te zombi konuları oluşabilir mi? (Neden / Neden olmasın?)
  3. Mümkünse, .NET'te bir zombi iş parçacığının oluşturulmasını nasıl zorlayabilirim?
  4. Mümkünse, .NET'te bir zombi iş parçacığı senaryosunu riske atmadan kilitlemeyi nasıl kullanabilirim?

Güncelleme

Bu soruyu iki yıldan biraz önce sordum. Bugün bu oldu:

Nesne bir zombi durumunda.


8
arkadaşınızın çıkmaza girmediğinden emin misiniz ??
Andreas Niedermair

10
@AndreasNiedermair - Kilitlenmenin ne olduğunu biliyorum ve bu terminolojinin yanlış kullanımı meselesi değildi. Konuşmada kilitlenme belirtildi ve "zombi dizisinden" açıkça farklıydı. Bana göre, ana ayrım, ölü bir kilidin iki yönlü çözülemez bir bağımlılığa sahip olması, zombi ipliğinin tek yönlü olması ve sonlandırılmış bir işlem gerektirmesidir. Eğer katılmıyorsanız ve bu şeylere bakmanın daha iyi bir yolu olduğunu düşünüyorsanız, lütfen açıklayın
smartcaveman

19
Bence "zombi" terimi aslında "zombi sürecinde" olduğu gibi bir UNIX artalan geliyor, doğru ??? UNIX bir "zombi süreci" açık bir tanımı yoktur: o sonlandırıldı ancak bir çocuk işlemini tarif Alt sürecin üst hala arayarak "açıklamasında" çocuk süreç gerekiyor (ve 's kaynaklar) nerede waitya waitpid. Alt sürece "zombi işlemi" denir. Ayrıca bkz. Howtogeek.com/119815
hogliux

9
Programınızın bir kısmı çökerse, programı tanımsız bir durumda bırakırsanız, elbette programınızın geri kalanıyla ilgili sorunlara neden olabilir. Tek iş parçacıklı bir programda istisnaları yanlış ele alırsanız da aynı şey olabilir. Sorun iş parçacığı ile ilgili değil, sorun, genel değişken durumu olması ve beklenmedik iş parçacığı sonlandırma düzgün işlemiyor olmasıdır. "Gerçekten parlak" iş arkadaşınız bu konuda tamamen kapalı.
Jim Mischel

9
"İlk bilgisayarlardan bu yana, makinede her zaman hayaletler vardı. Beklenmedik protokoller oluşturmak için bir araya gelen rastgele kod bölümleri ..."
Chris Laplante

Yanıtlar:


242
  • "Zombi parçacığının" burada açıkladığımdan daha net bir tanımı var mı?

Benim için oldukça iyi bir açıklama gibi görünüyor - sona eren (ve bu nedenle artık herhangi bir kaynak bırakamayan), ancak kaynakları (örneğin tutamaçlar) hala etrafta olan ve (potansiyel olarak) sorunlara neden olan bir iş parçacığı.

  • .NET'te zombi konuları oluşabilir mi? (Neden / Neden olmasın?)
  • Mümkünse, .NET'te bir zombi iş parçacığının oluşturulmasını nasıl zorlayabilirim?

Kesinlikle, bak, ben yaptım!

[DllImport("kernel32.dll")]
private static extern void ExitThread(uint dwExitCode);

static void Main(string[] args)
{
    new Thread(Target).Start();
    Console.ReadLine();
}

private static void Target()
{
    using (var file = File.Open("test.txt", FileMode.OpenOrCreate))
    {
        ExitThread(0);
    }
}

Bu program Targetbir dosyayı açan bir iş parçacığı başlatır ve hemen kullanarak kendini öldürür ExitThread. Sonuçta ortaya çıkan zombi iş parçacığı hiçbir zaman "test.txt" dosyasındaki tanıtıcıyı serbest bırakmaz ve bu nedenle program sonlanıncaya kadar dosya açık kalır (işlem gezgini veya benzeri bir yöntemle denetleyebilirsiniz). "Test.txt" tanıtıcısı çağrılıncaya kadar serbest bırakılmayacak GC.Collect- sapları sızdıran bir zombi iş parçacığı oluşturmayı düşündüğümden daha zor olduğu ortaya çıkıyor)

  • Mümkünse, .NET'te bir zombi iş parçacığı senaryosunu riske atmadan kilitlemeyi nasıl kullanabilirim?

Az önce yaptığım şeyi yapma!

Kodunuz kendisinden sonra doğru bir şekilde temizlendiği sürece ( yönetilmeyen kaynaklarla çalışırken Güvenli Kollar veya eşdeğer sınıflar kullanın) ve konuları garip ve harika yollarla öldürmek için yolunuzdan çıkmadığınız sürece (en güvenli yol sadece dişleri asla öldürmemek - kendilerini normal bir şekilde sonlandırmalarına veya gerekirse istisnalara izin verme), bir zombi ipliğine benzeyen bir şey elde etmenin tek yolu, bir şey çok yanlış gitmişse (örn. CLR'de bir şeyler ters giderse).

Aslında bir zombi iplik oluşturmak aslında şaşırtıcı derecede zordur (Ben esasında C dışında çağırmak değil esentially söyleyen bir fonksiyon içine P / Invoke zorunda kaldı). Örneğin, aşağıdaki (korkunç) kod aslında bir zombi iş parçacığı oluşturmaz.

static void Main(string[] args)
{
    var thread = new Thread(Target);
    thread.Start();
    // Ugh, never call Abort...
    thread.Abort();
    Console.ReadLine();
}

private static void Target()
{
    // Ouch, open file which isn't closed...
    var file = File.Open("test.txt", FileMode.OpenOrCreate);
    while (true)
    {
        Thread.Sleep(1);
    }
    GC.KeepAlive(file);
}

Oldukça korkunç hatalar yapmasına rağmen, "test.txt" tanıtıcısı Abortçağrılır çağrılmadan hala kapalıdır ( filekapakların altında dosya tanıtıcısını sarmak için SafeFileHandle kullanan sonlandırıcının bir parçası olarak )

C.Evenhuis cevabındaki kilitleme örneği, bir iş parçacığı tuhaf olmayan bir şekilde sonlandırıldığında bir kaynağı (bu durumda bir kilit) serbest bırakmanın en kolay yoludur, ancak bunun lockyerine bir ifade kullanılarak kolayca düzeltilebilir veya serbest bırakma bir finallyblok içinde.

Ayrıca bakınız


3
i bir backgroundworker kullanarak excel şeyler kaydetme ile oynarken hatırlıyorum (çünkü sadece hata ayıklama vb atlandı) her zaman tüm kaynakları yayınlanmadı. sonradan yaklaşık 50 excel süreci gördüm. zombieexcelprocesses oluşturdum mu?
Stefan

3
@Justin - +1 - Harika yanıt. ExitThreadAramanıza biraz şüpheci yaklaşıyorum . Açıkçası, işe yarıyor, ancak gerçekçi bir senaryodan daha akıllı bir numara gibi geliyor. Hedeflerimden biri, yanlışlıkla .NET kodu ile zombi konuları oluşturmamaları için ne yapmamam gerektiğini öğrenmektir. Muhtemelen .NET kodundan bu soruna neden olduğu bilinen C ++ kodunu çağırmanın istenen efekti ürettiğini anladım. Bu şeyler hakkında çok şey biliyorsunuz. Aynı sonuca sahip başka vakalar (muhtemelen garip, ancak istemeden gerçekleşmeyecek kadar tuhaf değil) biliyor musunuz?
smartcaveman

3
Yani cevap 'c # 4'te değil', değil mi? Bir zombi iplik almak için CLR'den atlamak zorunda kalırsanız, bir .Net sorunu gibi görünmüyor.
Gusdor

4
@Stefan neredeyse kesinlikle söylemezdim. Açıkladığınız şeyi birçok kez yaptım. Excel işlemleri, normal UI aracılığıyla hemen erişilemese de, hala çalışıyor oldukları için zombiler değildir. Bunları GetObject çağrılarıyla alabilmeniz gerekir . Set excelInstance = GetObject(, "Excel.Application")
Daniel

7
"Elde edilen zombi iş parçacığı" test.txt "dosyasına hiçbir zaman tanıtıcı serbest bırakmaz ve bu nedenle program sonlanıncaya kadar dosya açık kalır" yanlış. Küçük kanıt: `statik void Main (string [] args) {new Thread (GcCollect) .Start (); yeni Konu (Hedef) .Start (); Console.ReadLine (); } private static void Target () {using (var file = File.Open ("test.txt", FileMode.OpenOrCreate)) {ExitThread (0); }} özel statik boşluk GcCollect () {while (true) {Thread.Sleep (10000); GC.Collect (); }} `
Sinix

46

Cevabımı biraz temizledim, ancak referans için orijinali aşağıda bıraktım

Zombiler terimini ilk kez duydum, bu yüzden tanımının:

Tüm kaynaklarını serbest bırakmadan sona eren bir iş parçacığı

Bu tanım göz önüne alındığında, evet, bunu diğer dillerde olduğu gibi (C / C ++, java) .NET'te yapabilirsiniz.

Ancak , ben .NET, iş parçacığı kritik kod yazmak için iyi bir neden olduğunu sanmıyorum. .NET'e karar vermek için başka nedenler olabilir, ancak zombi iş parçacıklarının bir şekilde bana göre bir anlamı olmadığı için .NET'i yazmak. Zombi konuları C / C ++ 'da mümkündür (C'de karışıklık yapmanın çok daha kolay olduğunu bile iddia edebilirim) ve kritik, dişli uygulamaların birçoğu C / C ++ (yüksek hacimli ticaret, veritabanları vb.)

Sonuç Kullanılacak bir dile karar verme sürecindeyseniz, büyük resmi dikkate almanızı öneririm: performans, takım becerileri, zamanlama, mevcut uygulamalarla entegrasyon vb. Elbette, zombi konuları düşünmeniz gereken bir şeydir , ancak C gibi diğer dillerle karşılaştırıldığında .NET'te bu hatayı yapmak çok zor olduğu için, bu endişenin yukarıda belirtilenler gibi gölgelerle gölgesinde olacağını düşünüyorum. İyi şanslar!

Orijinal Yanıt Zombies , uygun iş parçacığı kodu yazmazsanız var olabilir. Aynı şey C / C ++ ve Java gibi diğer diller için de geçerlidir. Ancak bu, .NET'te dişli kod yazmamak için bir neden değildir.

Ve diğer tüm dillerde olduğu gibi, bir şey kullanmadan önce fiyatı öğrenin. Ayrıca, kaputun altında neler olduğunu bilmenize yardımcı olur, böylece olası sorunları önceden tahmin edebilirsiniz.

Kritik sistemler için güvenilir kod yazmak kolay değildir, hangi dilde olursanız olun. Ama olumlu bir şekilde .NET'te doğru yapmak imkansız değil. Ayrıca AFAIK, .NET iş parçacığı, C / C ++ 'da iş parçacığından farklı değildir, bazı .net'e özgü yapılar (RWL ve olay sınıflarının hafif sürümleri gibi) dışında aynı sistem çağrılarını kullanır (veya ondan oluşturulur).

zombiler terimini ilk kez duydum, ancak açıklamanıza dayanarak, iş arkadaşınız muhtemelen tüm kaynakları serbest bırakmadan sona eren bir iş parçacığı anlamına geliyordu. Bu, muhtemelen bir kilitlenmeye, bellek sızıntısına veya başka bir kötü yan etkiye neden olabilir. Bu açıkça arzu edilmez, ancak diğer dillerde de mümkün olduğundan bu olasılık nedeniyle .NET singling muhtemelen iyi bir fikir değildir. Hatta C / C ++ ile karıştırmanın .NET'ten daha kolay olduğunu iddia ediyorum (özellikle RAII'niz olmadığı C'de), ancak birçok kritik uygulama C / C ++ ile yazılmış değil mi? Bu gerçekten kişisel koşullarınıza bağlıdır. Eğer uygulamadan hız her ayrıntısını açığa çıkarmaktır istiyoruz ve yakın mümkün, daha sonra .NET çıplak metale almak istiyorsanız kudretinien iyi çözüm değil. Eğer sıkı bir bütçe ve / web hizmetleri ile arabirim .net kitaplıkları / vs mevcut bir sürü yaparsanız o zaman .NET olabilir iyi bir seçim.


(1) Çıkmaz externyöntemlere çarptığımda kaputun altında neler olduğunu nasıl anlayacağımı bilmiyorum . Eğer bir öneriniz varsa, bunu duymak isterim. (2) .NET ile yapmanın mümkün olduğunu kabul ediyorum. Kilitlemenin mümkün olduğuna inanmak istiyorum, ancak bugün bunu haklı çıkarmak için tatmin edici bir cevap bulamadım
smartcaveman

1
@smartcaveman, kastettiğiniz lockingşey lockanahtar kelime ise, muhtemelen yürütmeyi serileştirdiği için değil. Verimi en üst düzeye çıkarmak için, kodunuzun özelliklerine bağlı olarak doğru yapıları kullanmanız gerekir. Eğer c / c ++ / java / pthreads / boost / thread havuzları / ne olursa olsun güvenilir bir kod yazabilirseniz söyleyebilirim, o zaman da C # yazabilirsiniz. Ancak, herhangi bir kitaplığı kullanarak herhangi bir dilde güvenilir kod yazamıyorsanız, o zaman C # 'da yazmak farklı olacaktır.
Jerahmeel

@smartcaveman, kaputun altında ne olduğunu bulmak için, Google yığınlara yardımcı olur ve sorununuz web'de bulmak için çok egzotikse, reflektör çok kullanışlıdır. Ancak iş parçacığı sınıfları için MSDN belgelerini çok yararlı buluyorum. Ve birçoğu, C'de kullandığınız aynı sistem çağrıları için sadece sarmalayıcılardır.
Jerahmeel

1
@smartcaveman hiç değil, demek istediğim bu değil. Bu tarafa rastlarsa özür dilerim. Söylemek istediğim, kritik bir uygulama yazarken .NET'i yazmak için çok hızlı olmamalısınız. Elbette, zombi ipliklerinden çok daha kötü şeyler yapabilirdiniz (ki bu sadece yönetilmeyen herhangi bir kaynağı serbest bırakmayan, tamamen diğer dillerde gerçekleşebilecek konulardır: stackoverflow.com/questions/14268080/… ), ancak yine, bu .NET'in geçerli bir çözüm olmadığı anlamına gelmez.
Jerahmeel

2
.NET'in kötü bir teknoloji olduğunu düşünmüyorum. Aslında benim birincil gelişim çerçevem. Ancak, bu nedenle, duyarlı olduğu kusurları anlamam önemli. Temel olarak, .NET'i seçiyorum, ama hoşuma gittiğinden, sevmediğim için değil. (Ve endişelenme kardeşim, seni +
1'ledim

26

Şu anda cevabımın çoğu aşağıdaki yorumlarla düzeltildi. Cevabı silmeyeceğim çünkü itibar puanlarına ihtiyacım var çünkü yorumlardaki bilgiler okuyucular için değerli olabilir.

Immortal Blue, .NET 2.0 ve sonraki finallybloklarda iş parçacığı düşüklerine karşı bağışık olduğunu belirtti. Ve Andreas Niedermair tarafından yorumlandığı gibi, bu gerçek bir zombi parçacığı olmayabilir, ancak aşağıdaki örnek bir iş parçacığını iptal etmenin nasıl sorunlara neden olabileceğini göstermektedir:

class Program
{
    static readonly object _lock = new object();

    static void Main(string[] args)
    {
        Thread thread = new Thread(new ThreadStart(Zombie));
        thread.Start();
        Thread.Sleep(500);
        thread.Abort();

        Monitor.Enter(_lock);
        Console.WriteLine("Main entered");
        Console.ReadKey();
    }

    static void Zombie()
    {
        Monitor.Enter(_lock);
        Console.WriteLine("Zombie entered");
        Thread.Sleep(1000);
        Monitor.Exit(_lock);
        Console.WriteLine("Zombie exited");
    }
}

Ancak bir lock() { }blok kullanılırken a , bu şekilde tetiklendiğinde finallyde yürütülür ThreadAbortException.

Aşağıdaki bilgiler ortaya çıktığı gibi yalnızca .NET 1 ve .NET 1.1 için geçerlidir:

lock() { }Bloğun içinde başka bir istisna oluşursa ve ThreadAbortExceptiontam olarak finallyblok çalıştırılmak üzere geldiğinde , kilit serbest bırakılmaz. Bahsettiğiniz gibi, lock() { }blok şöyle derlenir:

finally 
{
    if (lockWasTaken) 
        Monitor.Exit(temp); 
}

Thread.Abort()Oluşturulan finallyblok içinde başka bir iş parçacığı ararsa , kilit serbest bırakılmayabilir.


2
hakkında konuşuyorsunuz lock()ama bunun herhangi bir kullanımını göremiyorum ... yani - bu nasıl bağlanır? Bunun "yanlış" kullanımıdır Monitor.Enterve Monitor.Exit(kullanımını eksik tryve finally)
Andreas Niedermair

4
Ben bir zombi-iş parçacığı demezdim - bu sadece yanlış bir kullanımı Monitor.Enterve Monitor.Exitdüzgün kullanımı tryve finallyher neyse, senaryonuzda asılı olabilecek diğer iş parçacıklarını kilitleyecektir _lock, bu yüzden bir zil sesi senaryosu var - mutlaka bir zombi iş parçacığı değil ... Ayrıca, kilidi serbest bırakmıyorsunuz Main... ama, hey ... belki OP zombi parçacıkları yerine kilitlenme için kilitliyor :)
Andreas Niedermair

1
@AndreasNiedermair belki de bir zombi iplik tanımı düşündüğüm gibi değil. Belki buna "yürütmeyi sonlandıran, ancak tüm kaynakları serbest bırakmayan bir iş parçacığı" diyebiliriz. Ödevimi silmek ve yapmak için caziptir, ancak OP senaryosuna benzerlik için cevabı saklar.
C.Evenhuis

2
Burada suç yok! Aslında cevabınız beni düşünmeye başladı :) OP açık bir şekilde serbest bırakılmayan kilitler hakkında konuştuğu için, eşinin ölü kilitleme hakkında konuştuğuna inanıyorum - çünkü bir kilit bir iş parçacığına bağlı gerçek bir kaynak değil ( paylaşılıyor ... nöna) - ve bu nedenle herhangi bir "zombi" iş parçacığından en iyi uygulamalara bağlı kalarak lockve uygun tryveya finally-kullanım kullanılarak kaçınılabilir
Andreas Niedermair

1
@ C.Evenhuis - Tanımımın doğru olduğundan emin değilim. Soruyu neden sorduğumun bir kısmı bunu temizlemek. Ben kavramı C / C ++ ağır adlandırılır düşünüyorum
smartcaveman

24

Bu Zombi konuları ile ilgili değil, ancak Etkili C # kitabında, ilginç bulabileceğinizi düşündüğüm Zombi nesneleri hakkında konuşan IDisposable, (madde 17) ile ilgili bir bölüm var.

Kitabın kendisini okumanızı tavsiye ederim, ama bunun özü, IDisposable'ı uygulayan veya bir Desctructor içeren bir sınıfınız varsa, her ikisinde de yapmanız gereken kaynakları serbest bırakmaktır. Burada başka şeyler yaparsanız, nesnenin çöp toplanmaması, aynı zamanda hiçbir şekilde erişilebilir olmaması ihtimali vardır.

Aşağıdakine benzer bir örnek verir:

internal class Zombie
{
    private static readonly List<Zombie> _undead = new List<Zombie>();

    ~Zombie()
    {
        _undead.Add(this);
    }
}

Bu nesne üzerindeki yıkıcı çağrıldığında, global listeye kendisine bir referans yerleştirilir, yani programın ömrü boyunca canlı ve bellekte kalır, ancak erişilebilir değildir. Bu, kaynakların (özellikle yönetilmeyen kaynaklar) tamamen serbest bırakılmayabileceği anlamına gelebilir ve bu da her türlü potansiyel soruna neden olabilir.

Daha eksiksiz bir örnek aşağıdadır. Foreach döngüsüne ulaşıldığında, Undead listesinde her biri bir görüntü içeren 150 nesneniz olur, ancak görüntü GC'd'dir ve kullanmaya çalışırsanız bir istisna alırsınız. Bu örnekte, bir ArgumentException alıyorum (Parametre geçerli değil), görüntüyü bir şey yapmaya çalıştığımda, kaydetmeye çalışsam da, hatta yükseklik ve genişlik gibi boyutları bile görüntülüyorum:

class Program
{
    static void Main(string[] args)
    {
        for (var i = 0; i < 150; i++)
        {
            CreateImage();
        }

        GC.Collect();

        //Something to do while the GC runs
        FindPrimeNumber(1000000);

        foreach (var zombie in Zombie.Undead)
        {
            //object is still accessable, image isn't
            zombie.Image.Save(@"C:\temp\x.png");
        }

        Console.ReadLine();
    }

    //Borrowed from here
    //http://stackoverflow.com/a/13001749/969613
    public static long FindPrimeNumber(int n)
    {
        int count = 0;
        long a = 2;
        while (count < n)
        {
            long b = 2;
            int prime = 1;// to check if found a prime
            while (b * b <= a)
            {
                if (a % b == 0)
                {
                    prime = 0;
                    break;
                }
                b++;
            }
            if (prime > 0)
                count++;
            a++;
        }
        return (--a);
    }

    private static void CreateImage()
    {
        var zombie = new Zombie(new Bitmap(@"C:\temp\a.png"));
        zombie.Image.Save(@"C:\temp\b.png");
    }
}

internal class Zombie
{
    public static readonly List<Zombie> Undead = new List<Zombie>();

    public Zombie(Image image)
    {
        Image = image;
    }

    public Image Image { get; private set; }

    ~Zombie()
    {
        Undead.Add(this);
    }
}

Yine, özellikle zombi konuları hakkında soru sorduğunuzun farkındayım, ancak soru başlığı .net'teki zombilerle ilgili ve bunu hatırlattım ve başkalarının ilginç bulabileceğini düşündüm!


1
Bu ilginç. _undeadStatik olması mı gerekiyor?
smartcaveman

1
Bu yüzden denedim, "yıkılmış" nesneden bazı baskılar. Ona normal bir nesne gibi davranır. Bunu yapmak konusunda sorunlu bir şey var mı?
smartcaveman

1
Cevabımı, sorunu biraz daha açık bir şekilde gösteren bir örnekle güncelledim.
JMK

1
Neden aşağı indirildiğini bilmiyorum. Yararlı buldum. İşte bir soru - ne tür bir istisna alacaksınız? Bunun bir olmasını beklemiyorum NullReferenceException, çünkü eksik şeyin uygulamaya göre makineye daha fazla bağlı olması gerektiğini hissediyorum. Bu doğru mu?
smartcaveman

4
Elbette sorun o kadar IDisposableda değil . Sonlandırıcılar (yıkıcılar) ile ilgileniyorum ama sadece IDisposablebir nesneyi sonlandırıcı kuyruğuna gitmeyecek ve bu zombi senaryosunu riske atmayacağım. Bu uyarı sonlandırıcılarla ilgilidir ve Dispose yöntemleri olarak adlandırılabilir. IDisposableKesinleştirici olmayan tiplerde kullanılan örnekler vardır . Duygu, kaynak temizliği için olmalıdır, ancak bu önemsiz olmayan kaynak temizliği olabilir. RX geçerli IDisposableolarak abonelikleri temizlemek için kullanılır ve diğer alt kaynakları arayabilir. (Ben de ya btw aşağı ...)
James World

21

Ağır yük altındaki kritik sistemlerde, kilitsiz kod yazmak, öncelikle performans iyileştirmeleri nedeniyle daha iyidir. LMAX gibi şeylere ve bunun büyük tartışmalar için "mekanik sempati" den nasıl yararlandığına bakın. Zombi konuları hakkında endişeleniyor musunuz? Bence bu sadece ütülenecek bir hata ve kullanmamak için yeterince iyi bir neden değil lock.

Arkadaşın daha çok süslü ve karanlık egzotik terminoloji bilgisini bana gösteriş yapıyor gibi görünüyor! Microsoft UK'deki performans laboratuvarlarını çalıştırırken, .NET'te bu sorunun bir örneğiyle hiç karşılaşmadım.


2
Bence farklı deneyimler bizi farklı böcekler hakkında paranoyak yapıyor. Bunu açıklarken aşırı uç bir durum olduğunu kabul etti, ancak gerçekten bir uç durum ve asla durum değilse, en azından biraz daha iyi anlamak istiyorum
Girişiniz

1
Yeterince adil. Beyanla ilgili orantısız bir şekilde endişelenmeni istemem lock!
James World

1
Bu konuyu daha iyi anlasaydım çok daha az endişeliydim.
smartcaveman

4
Ben, çok fazla olan bazı iplik-FUD kurtulmak için çalışıyorum çünkü oy verdim. Lock-FUD atmak için daha fazla iş alacak :) Sadece devs sınırsız bir spinlock (performans için) almak, böylece geniş bir kuyruğa 50K veri kopyalamak için koparmak.
Martin James

3
Evet, hem genel hem de özel olarak. Doğru kilitsiz kod yazmak, programlamanın kazandığı kadar zordur. Deneyimlerime göre, vakaların büyük çoğunluğu için, büyük taneli kurs taneli (nispeten) anlaşılması kolay lockbloklar gayet iyi. İhtiyacınız olduğunu bilinceye kadar performans optimizasyonu uğruna karmaşıklık getirmekten kaçınırım.
James World

3

Burada açıkladığımdan daha iyi bir "zombi ipliği" tanımı var mı?

"Zombi İplikleri" var olduğunu kabul ediyorum, bırakmadıkları kaynaklarla bırakılan ve henüz tamamen ölmeyen Threads ile neler olduğunu ifade eden bir terimdir, dolayısıyla "zombi" adı, Bu tavsiyenin açıklaması para konusunda oldukça doğru!

.NET üzerinde zombi iş parçacıkları oluşabilir? (Neden / Neden olmasın?)

Evet olabilirler. Bu bir referanstır ve aslında Windows tarafından "zombi" olarak adlandırılır: MSDN, Ölü işlemler / iş parçacıkları için "Zombi" sözcüğünü kullanır

Sık sık olmak başka bir hikaye, ve Kod Kilitleme gibi sizin için olduğu gibi kodlama teknik ve uygulamalarınıza bağlıdır ve bir süredir yapmış olduğunuz senaryo için bile endişelenmeyeceğim.

Ve Evet, @KevinPanko'nun yorumlarda doğru şekilde belirtildiği gibi, "Zombie Threads" Unix'ten geliyor, bu yüzden XCode-ObjectiveC'de kullanılıyor ve "NSZombie" olarak adlandırılıyor ve hata ayıklama için kullanılıyor. Hemen hemen aynı şekilde davranır ... tek fark, ölmeniz gereken bir nesnenin, hata ayıklama için kodunuzda potansiyel bir sorun olabilecek "Zombie Thread" yerine "ZombieObject" haline gelmesidir.


1
Ancak MSDN'nin zombi kullanma şekli, bu sorunun kullanma biçiminden çok farklıdır.
Ben Voigt

1
Oh evet, katılıyorum, ama MSDN bile Zombie Threads olarak konuları ifade ettiğinde bir noktaya geliyordu. ve gerçekte meydana gelebildiklerini.
SH

4
Elbette, ancak iş parçacığı tutulduğunda çıkarken kaynaklara yönelik değil, iş parçacığına hala bir tutamacı tutan başka bir koda atıfta bulunur. Sorunun tanımını kabul ederek ilk cümleniz yanlış olan şeydir.
Ben Voigt

1
Ne demek istediğini anlıyorum. Dürüst olmak gerekirse bunu fark etmedim bile. Nasıl olduğuna bakılmaksızın, tanımın var olduğu noktasına odaklanıyordum. Tanımın, iş parçacığına ne olduğu değil, nasıl yapıldığından kaynaklandığını unutmayın.
SH

0

Zombi ipliklerini yeterince kolayca yapabilirim.

var zombies = new List<Thread>();
while(true)
{
    var th = new Thread(()=>{});
    th.Start();
    zombies.Add(th);
}

Bu, iplik tutamaçlarını (için Join()) sızdırıyor . Bu, yönetilen dünyada endişe duyduğumuz bir başka bellek sızıntısı.

Şimdi, bir ipliği gerçekten kilitleri tutacak şekilde öldürmek arkada bir acıdır, ancak mümkündür. Diğer adam ExitThread()işi yapar. Bulduğu gibi, dosya tanıtıcısı gc tarafından temizlendi, ancak lockbir nesnenin etrafında olmaz. Ama bunu neden yaptın?

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.