Чи існують зомбі ... у .NET?


385

У мене була дискусія з товаришем по команді щодо блокування в .NET. Він справді яскравий хлопець з великим досвідом як програмування нижчого, так і вищого рівня, але його досвід роботи з програмуванням нижчого рівня набагато перевищує мій. У будь-якому випадку, він стверджував, що слід уникати блокування .NET у критичних системах, які, як очікується, знаходяться під великим навантаженням, якщо це взагалі можливо, щоб уникнути малоймовірності збою системи "потоки зомбі". Я звичайно використовую блокування, і я не знав, що таке "тема зомбі", тому я запитав. Враження, яке я отримав від його пояснення, полягає в тому, що зомбі-нитка - це нитка, яка закінчилася, але якимось чином все ще тримається на деяких ресурсах. Приклад, який він наводив, як зомбі-нитка може зламати систему, це те, що починається певна процедура після блокування на якомусь об'єкті, а потім в якийсь момент припиняється до того, як замок можна буде звільнити. Ця ситуація може призвести до краху системи, оскільки врешті-решт, спроби виконання цього методу призведуть до того, що потоки очікують на доступ до об'єкта, який ніколи не буде повернутий, оскільки потік, який використовує заблокований об'єкт, мертвий.

Я думаю, що я отримав суть цього, але якщо я не в базі, будь ласка, повідомте мене. Концепція мала для мене сенс. Я не був повністю переконаний, що це справжній сценарій, який може статися в .NET. Я ніколи раніше не чув про "зомбі", але я усвідомлюю, що програмісти, які працювали в глибині на нижчих рівнях, як правило, глибше розуміють основи обчислень (як, наприклад, нитки). Я, безумовно, бачу цінність блокування, і я бачив, що багато програмістів світового класу використовують механізм блокування. Я також маю обмежені можливості оцінювати це для себе, тому що я знаю, що lock(obj)твердження насправді є лише синтаксичним цукром для:

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

і тому, що Monitor.Enterі Monitor.Exitпозначені extern. Здається, що .NET робить якусь обробку, яка захищає потоки від впливу компонентів системи, які могли б мати такий вплив, але це суто спекулятивно і, ймовірно, просто ґрунтується на тому, що я ніколи не чув про "зомбі-потоки" раніше. Отож, я сподіваюся, що я можу отримати відгуки про це тут:

  1. Чи є чіткіше визначення поняття "зомбі", ніж те, що я пояснив тут?
  2. Чи можуть з'являтися теми. Зомбі в .NET? (Чому / чому ні?)
  3. Як застосовано, як я можу змусити створити нитку зомбі в .NET?
  4. Якщо можливо, як я можу використовувати блокування, не ризикуючи сценарієм потоку зомбі у .NET?

Оновлення

Я задав це питання трохи більше двох років тому. Сьогодні це сталося:

Об'єкт знаходиться в зомбі-стані.


8
ти впевнений, що твій товариш по службі не говорить про тупиковість ??
Андреас Нідермайр

10
@AndreasNiedermair - Я знаю, що таке тупикова ситуація, і явно не було питанням зловживання цією термінологією. Тупик згадувався в розмові і чітко відрізнявся від "зомбі-нитки". Для мене головна відмінність полягає в тому, що мертвий замок має двосторонню нерозв’язну залежність, тоді як зомбі-нитка є односторонньою і вимагає припинення процесу. Якщо ви не погоджуєтесь і вважаєте, що є кращий спосіб поглянути на ці речі, поясніть, будь ласка,
smartcaveman

19
Я думаю, що термін "зомбі" насправді походить від зворотного зв'язку UNIX, як у "зомбі-процесі", правда ??? У UNIX існує чітке визначення поняття "процес зомбі": він описує дочірній процес, який закінчився, але там, де батькові дочірнього процесу все ще потрібно "звільнити" дочірній процес (і це ресурси), зателефонувавши waitабо waitpid. Потім дочірній процес називається "зомбі-процесом". Дивіться також howtogeek.com/119815
hogliux

9
Якщо частина вашої програми виходить з ладу, залишаючи програму у невизначеному стані, це, звичайно, може спричинити проблеми з рештою програми. Те саме може статися, якщо ви неправильно обробляєте винятки в однопотоковій програмі. Проблема не в потоках, проблема полягає в тому, що у вас глобальний стан змін і що ви неправильно обробляєте несподіване завершення потоку. Ваш "дійсно яскравий" колега зовсім не базується на цьому.
Джим Мішель

9
"Ще з перших комп'ютерів у машині завжди були привиди. Випадкові сегменти коду, які згрупувались для формування несподіваних протоколів ..."
Кріс Лаплант

Відповіді:


242
  • Чи є чіткіше визначення поняття "зомбі", ніж те, що я пояснив тут?

Мені здається досить гарним поясненням - потік, який припинився (і тому більше не може випускати жодних ресурсів), але ресурси якого (наприклад, ручки) все ще існують і (можливо) спричиняють проблеми.

  • Чи можуть з'являтися теми. Зомбі в .NET? (Чому / чому ні?)
  • Як застосовано, як я можу змусити створити нитку зомбі в .NET?

Вони точно так, дивіться, я зробив один!

[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);
    }
}

Ця програма запускає потік, Targetякий відкриває файл, а потім негайно вбиває себе за допомогою ExitThread. Отриманий потік зомбі ніколи не випустить ручку до файлу "test.txt", і таким чином файл буде залишатися відкритим, поки програма не припиниться (ви можете перевірити провідник процесів чи подібне). Ручка до "test.txt" не буде випущена доти, доки GC.Collectвона не буде викликана - виявляється, це навіть складніше, ніж я думав, створити зомбі-нитку, яка просочується ручками)

  • Якщо можливо, як я можу використовувати блокування, не ризикуючи сценарієм потоку зомбі у .NET?

Не роби того, що я щойно робив!

Поки ваш код очиститься після себе правильно (використовуйте Безпечні ручки або еквівалентні класи, якщо працюєте з некерованими ресурсами), і поки ви не виходите зі шляху, щоб вбивати нитки дивними та чудовими способами (найбезпечніший спосіб - це просто щоб не вбивати нитки - нехай припинити себе нормально, або через виключення в разі необхідності), єдиним способом , що ви будете мати що - щось схоже на зомбі нитки, якщо що - то пішло дуже неправильно (наприклад , що - щось піде не так в CLR).

Насправді, насправді складно створити зомбі-нитку (мені довелося перейти до / функціонувати у функції, яка по суті каже вам у документації не називати її поза С). Наприклад, наступний (жахливий) код насправді не створює нитки зомбі.

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);
}

Незважаючи на те, що робив досить жахливі помилки, ручка до "test.txt" залишається закритою, як тільки Abortвикликається (як частина фіналізатора, для fileякого під обкладинками використовується SafeFileHandle, щоб обернути свою файлову ручку)

Приклад блокування у відповіді C.Evenhuis - це, мабуть, найпростіший спосіб не випустити ресурс (блокування в даному випадку), коли потік завершується незвичайним чином, але це легко виправити, використовуючи lockзамість цього оператор, або розміщення релізу в finallyблоці.

Дивись також


3
Я пам'ятаю, коли я грав зі збереженням матеріалів у програмі excel, використовуючи фонового працівника, я весь час не випускав усіх ресурсів (тому що я просто пропустив налагодження тощо). в диспетчері завдань я побачив після цього близько 50 процесів Excel. я створив zombieexcelпроцеси?
Стефан

3
@Justin - +1 - Чудова відповідь. Я хоч трохи скептично ставлюсь до вашого ExitThreadдзвінка. Очевидно, це працює, але це більше схоже на розумну хитрість, ніж на реалістичний сценарій. Однією з моїх цілей є навчитися чого не робити, щоб я випадково не створив зомбі-потоки з кодом .NET. Я, певно, міг зрозуміти, що виклик коду C ++, який, як відомо, викликає цю проблему з коду .NET, дасть бажаний ефект. Ви, очевидно, багато знаєте про цей матеріал. Чи знаєте ви про будь-які інші випадки (можливо, дивні, але недостатньо дивні, щоб ніколи не траплялися ненавмисно) з тим самим результатом?
smartcaveman

3
Отже, відповідь "не в c # 4", правда? Якщо вам доведеться вискочити з CLR, щоб отримати нитку зомбі, це не здається проблемою .Net.
Гусдор

4
@Stefan я б сказав, що майже напевно ні. Я робив те, що ви описували багато разів. Процеси Excel не є зомбі, оскільки вони все ще працюють, хоча і не доступні відразу через звичайний інтерфейс користувача. Ви можете отримати їх за допомогою дзвінків до GetObject . Set excelInstance = GetObject(, "Excel.Application")
Даніель

7
"Отриманий потік зомбі ніколи не випустить ручку до файлу" test.txt "і тому файл буде залишатися відкритим, поки програма не завершиться" невірно. Невеликий доказ: `static void Main (string [] args) {new Thread (GcCollect) .Start (); нова нитка (ціль) .Start (); Console.ReadLine (); } приватна статична void Target () {using (var file = File.Open ("test.txt", FileMode.OpenOrCreate)) {ExitThread (0); }} приватна статична порожнеча GcCollect () {while (true) {Thread.Sleep (10000); GC.Collect (); }} `
Sinix

46

Я трохи прояснив свою відповідь, але для посилання залишив оригінал нижче

Це перший раз, коли я чув про термін зомбі, тому припускаю його визначення:

Потік, який припинився, не звільняючи всіх своїх ресурсів

Отже, враховуючи це визначення, тоді так, ви можете зробити це в .NET, як і в інших мовах (C / C ++, java).

Однак я не вважаю це гарною причиною не писати потоковий, критичний код місії у .NET. Можливо, існують інші причини, щоб вирішити. Теми зомбі можливі в C / C ++ (я навіть заперечую, що набагато простіше зіпсувати C) і багато критичних додатків з потоками є в C / C ++ (великі обсяги торгівлі, бази даних тощо).

Висновок Якщо ви вирішили використовувати мову, то я пропоную вам врахувати велику картину: продуктивність, навички роботи в команді, графік роботи, інтеграція з існуючими програмами тощо. , але оскільки насправді зробити цю помилку в .NET порівняно з іншими мовами, такими як C, так важко, я думаю, що ця проблема буде затьмарена іншими речами, такими, як згадані вище. Удачі!

Оригінальний відповідь Zombies може існувати, якщо ви не пишете належний код для нарізки. Те саме стосується інших мов, таких як C / C ++ та Java. Але це не привід не писати потоковий код у .NET.

І так само, як і на будь-якій іншій мові, дізнайтеся ціну, перш ніж щось використовувати. Це також допомагає дізнатися, що відбувається під кришкою, щоб ви могли передбачити будь-які можливі проблеми.

Надійний код для критично важливих систем не так просто написати, якою б мовою ви не працювали. Але я впевнений, що це зробити неможливо правильно. Також AFAIK, .NET нарізка не так відрізняється від нанизування в C / C ++, вона використовує (або будується з) тих же системних викликів, за винятком деяких .net-специфічних конструкцій (наприклад, легкої версії RWL та класів подій).

вперше я чув про термін зомбі, але, виходячи з вашого опису, ваш колега, ймовірно, мав на увазі тему, яка припиняється, не випускаючи всіх ресурсів. Це може призвести до тупикової ситуації, витоку пам’яті чи іншого поганого побічного ефекту. Це, очевидно, не бажано, але виділяти .NET через таку можливість , мабуть, не є хорошою ідеєю, оскільки це можливо і в інших мовах. Я б навіть заперечував, що в C / C ++ легше зіпсуватись, ніж у .NET (особливо це стосується C, де у вас немає RAII), але в C / C ++ написано багато критичних програм? Тож це дійсно залежить від ваших індивідуальних обставин. Якщо ви хочете витягти кожну унцію швидкості зі свого додатку і хочете максимально наблизитися до чистого металу, то .NET можене бути найкращим рішенням. Якщо ви обмежуєте бюджет і чимало взаємодієте з веб-службами / існуючими .net-бібліотеками / тощо, то .NET може бути хорошим вибором.


(1) Я не впевнений, як зрозуміти, що відбувається під кришкою, коли я потрапив у тупикові externметоди. Якщо у вас є пропозиція, я хотів би почути її. (2) Я погоджуюся, що це можливо зробити у .NET. Я хотів би повірити, що це можливо з блокуванням, але я ще не знайшов задовольняючої відповіді, щоб виправдати це сьогодні
smartcaveman

1
@smartcaveman якщо то , що ви маєте в виду lockingце lockключове слово, то , можливо , не так як він упорядковує виконання. Для максимальної пропускної здатності вам доведеться використовувати правильні конструкції залежно від характеристик вашого коду. Я б сказав, якщо ви можете написати надійний код у c / c ++ / java / що завгодно, використовуючи pthreads / boost / thread пули / що завгодно, тоді ви можете також написати його на C #. Але якщо ви не можете написати надійний код будь-якою мовою, використовуючи будь-яку бібліотеку, я сумніваюся, що запис у C # буде інакшим.
Єрахмейл

@smartcaveman, що стосується з'ясування того, що знаходиться під кришкою, google допомагає купувати, і якщо у вас проблема занадто екзотична, щоб знайти її в Інтернеті, рефлектор дуже зручний. Але для занять з нитки я вважаю документацію MSDN дуже корисною. І багато з цього - лише обгортки для тих же системних викликів, які ви використовуєте в C-away.
Jerahmeel

1
@smartcaveman зовсім не так, це я не мав на увазі. Вибачте, якщо це трапилося саме так. Що я хотів сказати, це те, що ви не повинні надто швидко списати .NET при написанні критичної програми. Звичайно, ви можете зробити речі, які, можливо, набагато гірші, ніж зомбі-потоки (на мою думку, це лише теми, які не випускають жодних некерованих ресурсів, що цілком може статися на інших мовах: stackoverflow.com/questions/14268080/… ), але знову ж таки, це не означає, що .NET не є життєздатним рішенням.
Jerahmeel

2
Я не думаю, що .NET взагалі погана технологія. Це фактично моя основна рамка розвитку. Але через це я думаю, що важливо, щоб я розумів недоліки, до яких він сприйнятливий. В основному, я виділяю .NET, але тому, що мені це подобається, а не тому, що мені це не подобається. (І не хвилюйтесь брате, я + 1-ед ви)
smartcaveman

26

Зараз більшість моєї відповіді було виправлено коментарями нижче. Я не видаляю відповідь, тому що мені потрібні точки репутації, оскільки інформація в коментарях може бути цінною для читачів.

Безсмертний Блакитний зазначив, що в .NET 2.0 і вище finallyблоки не захищені від переривання потоку. І як коментує Андреас Нідермайр, це може бути не фактичною зомбі-потоком, але наступний приклад показує, як переривання теми може спричинити проблеми:

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");
    }
}

Однак при використанні lock() { }блоку, функція finallyвсе одно буде виконуватися, коли ThreadAbortExceptionвипущено a таким чином.

Наступна інформація, як виявляється, справедлива лише для .NET 1 та .NET 1.1:

Якщо всередині lock() { }блоку трапляється інший виняток, і він ThreadAbortExceptionнадходить саме тоді, коли finallyзбирається запустити блок, блокування не відпускається. Як ви вже згадували, lock() { }блок складається як:

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

Якщо інший потік дзвонить Thread.Abort()всередину генерованого finallyблоку, блокування може не звільнитися.


2
Ви говорите про це, lock()але я не бачу використання цього використання ... так - як це пов'язано? це "неправильне" використання Monitor.Enterта Monitor.Exit(відсутність використання tryта finally)
Andreas Niedermair

4
Я б не закликав цей зомбі-потік - це просто неправильне використання Monitor.Enterта Monitor.Exitбез належного використання tryта finally- у будь-якому випадку, ваш сценарій блокує інші потоки, на яких може бути зациклено _lock, тому існує сценарій тупикової ситуації - не обов'язково зомбі-потік ... Крім того, ви не відпускаєте замок у Main... але, ей ... можливо, ОП блокується для глухого блокування замість ниток-зомбі :)
Andreas Niedermair

1
@AndreasNiedermair, можливо, визначення потоку зомбі - це не зовсім те, що я думав. Можливо, ми можемо назвати це "потоком, який припинив виконання, але не випустив усіх ресурсів". Спокусився видалити і виконати домашнє завдання, але зберігаючи відповідь на схожість зі сценарієм ОП.
C.Evenhuis

2
тут немає образи! насправді у вашій відповіді я просто змусив задуматися над цим :) оскільки ОП відверто говорить про те, що замки не звільняються, я вважаю, що його співрозмовник говорив про мертве блокування - тому що замок - це не реальний ресурс, який пов'язаний з потоком ( це спільне ... nöna) - і тому будь-яку "зомбіну" нитку можна уникнути, дотримуючись найкращих практик та використовуючи lockабо належну try/ finally-використання
Андреас Нідермайр

1
@ C.Evenhuis - Я не впевнений, що моє визначення точне. Частина, чому я задаю питання, - це прояснити це. Я думаю, що ця концепція дуже згадується в C / C ++
smartcaveman

24

Йдеться не про теми Zombie, але в книзі «Ефективний C #» є розділ про реалізацію IDisposable (пункт 17), в якому йдеться про об’єкти Zombie, які, на мою думку, вам можуть бути цікавими.

Я рекомендую прочитати саму книгу, але суть її полягає в тому, що якщо у вас є клас, який реалізує IDisposable, або містить Desctructor, єдине, що вам слід зробити, - це звільнення ресурсів. Якщо ви робите тут інші речі, то є ймовірність, що об’єкт не буде збирати сміття, але також не буде доступний жодним чином.

Він наводить приклад, подібний до наведеного нижче:

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

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

Коли викликається деструктор на цьому об'єкті, посилання на себе міститься у глобальному списку, тобто він залишається живим та запам'ятовується протягом життя програми, але недоступний. Це може означати, що ресурси (особливо некеровані ресурси) можуть не бути повністю звільнені, що може спричинити всілякі потенційні проблеми.

Більш повний приклад наведено нижче. До моменту досягнення циклу foreach у вас є 150 об'єктів у списку Undead, кожен з яких містить зображення, але зображення було GC'd, і ви отримуєте виняток, якщо намагаєтесь його використовувати. У цьому прикладі я отримую ArgumentException (параметр недійсний), коли я намагаюся зробити щось із зображенням, чи намагаюся я його зберегти, або навіть переглянув розміри, такі як висота та ширина:

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);
    }
}

Знову ж таки, мені відомо, що ви питали про теми зомбі зокрема, але назва питання стосується зомбі в .net, і мені про це нагадали, і я думав, що іншим це може бути цікавим!


1
Це цікаво. Є _undeadзначить бути статичним?
smartcaveman

1
Тож я спробував це, з деякою роздрукуванням «знищеного» об’єкта. Він ставиться до цього як до звичайного об’єкта. Чи є щось проблематичне в цьому?
smartcaveman

1
Я оновив свою відповідь прикладом, який, сподіваюся, демонструє проблему дещо чіткіше.
JMK

1
Я не знаю, чому ти знявся. Я вважаю це корисним. Ось питання - який виняток ви збираєтеся отримати? Я не сподіваюся, що це буде так NullReferenceException, тому що я відчуваю, що відсутню річ потрібно більше прив’язати до машини, ніж до програми. Чи це правильно?
smartcaveman

4
Звичайно, це не стільки IDisposableв цьому питання. Я хвилююся щодо фіналізаторів (деструкторів), але просто не маючи IDisposableзмусити об’єкт перейти до черги на фіналізатор і ризикувати цим сценарієм зомбі. Це попередження стосується фіналізаторів, і вони можуть викликати методи утилізації. Є приклади, коли IDisposableвикористовується у типах без фіналізаторів. Настрій повинен бути очищений від ресурсів, але це може бути нетривіальним очищенням ресурсів. RX дійсно використовує IDisposableдля очищення підписок і може зателефонувати на інші ресурси нижче. (Я не порушив жодної btw ...)
James World

21

У критичних системах, що знаходяться під великим навантаженням, писати незаблокований код краще насамперед через поліпшення продуктивності. Подивіться на такі речі, як LMAX, і як він використовує "механічну симпатію" для великого обговорення цього питання. Хоча турбуєтесь про зомбі нитки? Я думаю, що це крайній випадок, який просто помилка, яку потрібно прасувати, і не достатньо вагомий привід не використовувати lock.

Звучить більше, як твій друг просто фантазує і виставляє свої знання про незрозумілу екзотичну термінологію для мене! За весь час, коли я працював у Microsoft UK в лабораторіях, я ніколи не стикався з примірником цієї проблеми в .NET.


2
Я думаю, що різні набори досвіду роблять нас параноїчними щодо різних помилок. Він визнав, що це крайній крайній випадок, пояснюючи це, але якщо це справді крайній випадок, а не випадковий, я хотів би принаймні трохи зрозуміти це - Дякую за ваш внесок
smartcaveman

1
Справедливо. Я просто не хотів би, щоб ви непропорційно турбувалися про lockзаяву!
Джеймс Світ

1
Я б набагато менше хвилювався, якби я глибше розумів це питання.
smartcaveman

4
Я підтримав те, що ви намагаєтеся позбутися деяких потоків-FUD, яких дуже багато. Lock-FUD займе більше роботи, щоб утилізувати :) Я просто притискаюсь, коли розробники беруть необмежений спінлок (для продуктивності), щоб вони змогли скопіювати 50K даних на широку чергу.
Мартін Джеймс

3
Так, і в загальному, і в конкретному. Введення правильного коду без блокування є настільки ж складним, як і програмування. З мого досвіду для переважної більшості випадків, великі жирові зернові (відносно) легкі для розуміння lockблоки просто чудові. Я б уникнув складності заради оптимізації продуктивності, доки не знатимеш, що потрібно.
James World

3

1. Чи є чіткіше визначення поняття "зомбі", ніж те, що я пояснив тут?

Я погоджуюся, що "Zombie Threads" існує, це термін для позначення того, що відбувається з теми, які залишилися з ресурсами, які вони не відпускають і поки не вмирають повністю, звідси назва "зомбі", так що ваша пояснення цього направлення досить правильно на гроші!

2.Чи можуть з'являтися потоки зомбі в .NET? (Чому / чому ні?)

Так, вони можуть статися. Це посилання, і насправді Windows називається "зомбі": MSDN використовує слово "зомбі" для мертвих процесів / потоків

Часто трапляється це вже інша історія, і це залежить від ваших методів і методів кодування, так як для вас, яким подобається блокування потоків і які ви робили це на деякий час, я б навіть не хвилювався, що з вами трапиться такий сценарій.

І так, як @KevinPanko правильно зазначав у коментарях, "Zombie Threads" походять від Unix, тому вони використовуються в XCode-ObjectiveC і називаються "NSZombie" і використовуються для налагодження. Він поводиться майже так само ... Єдина відмінність полягає в тому, що об'єкт, який повинен був померти, стає "ZombieObject" для налагодження замість "Zombie Thread", що може бути потенційною проблемою у вашому коді.


1
Але те, як MSDN використовує зомбі , сильно відрізняється від способу використання цього питання.
Бен Войгт

1
О так, я згоден, але я зазначав, що навіть MSDN посилається на теми як Зомбі-потоки, коли вони мертві. і що вони насправді можуть відбутися.
SH

4
Звичайно, але він має на увазі якийсь інший код, який все ще тримає ручку до потоку, а не потік, що тримає ручки до ресурсів, коли він вийшов. Ваше перше речення, погоджуючись з визначенням у питанні, - це те, що не так.
Бен Войгт

1
Ах, я бачу ваш погляд. Якщо чесно, я цього навіть не помічав. Я зосереджувався на його думці, що визначення існує, незалежно від того, як це відбувається. Пам’ятайте, що визначення існує через те, що відбувається з потоком, а не як це робиться.
SH

0

Я можу зробити нитки зомбі досить легко.

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

Це протікає ручками різьби (для Join()). Це просто чергове витік пам'яті, наскільки ми стурбовані в керованому світі.

Тепер, вбити нитку таким чином, що вона фактично тримає замки, це біль в тилу, але можливо. Інший хлопець ExitThread()робить свою роботу. Як він виявив, обробку файлів очистив gc, але lockнавколо об'єкта не буде. Але чому б ти це робив?

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.