.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.EnterMonitor.Exit표시됩니다 extern. .NET은 이러한 종류의 영향을 미칠 수있는 시스템 구성 요소에 대한 노출로부터 스레드를 보호하는 일종의 처리를 수행 할 수 있지만 순전히 추측 적이며 아마도 "좀비 스레드"에 대해 들어 본 적이 없다는 사실을 기반으로합니다. 전에. 따라서 여기에 대한 의견을 얻을 수 있기를 바랍니다.

  1. 여기서 설명한 것보다 "좀비 스레드"에 대한 명확한 정의가 있습니까?
  2. 좀비 스레드가 .NET에서 발생할 수 있습니까? (왜 왜 안돼?)
  3. 해당되는 경우 .NET에서 좀비 스레드를 작성하려면 어떻게해야합니까?
  4. 해당되는 경우 .NET에서 좀비 스레드 시나리오에 영향을주지 않으면 서 잠금을 어떻게 활용할 수 있습니까?

최신 정보

나는 2 년 전에이 질문을 조금했다. 오늘 이것은 일어났다 :

개체가 좀비 상태입니다.


8
동료가 교착 상태에 대해 이야기하지 않습니까?
Andreas Niedermair

10
@AndreasNiedermair-교착 상태가 무엇인지 알고 있으며 해당 용어를 잘못 사용하는 것은 아닙니다. 교착 상태는 대화에서 언급되었으며 "좀비 실"과는 분명히 다릅니다. 저에게 주요 차이점은 데드락은 해결 불가능한 양방향 의존성을 가지고 있지만 좀비 스레드는 단방향이며 종료 된 프로세스가 필요하다는 것입니다. 동의하지 않고 이러한 것들을 보는 더 좋은 방법이 있다고 생각하면 설명하십시오.
smartcaveman

19
"좀비"라는 용어는 실제로 "좀비 프로세스"에서와 같이 실제로 UNIX backgound에서 온 것 같습니다. UNIX에서 "좀비 프로세스"의 명확한 정의가있다 : 그것은 종료하지만 한 자식 프로세스를 설명하는 자식 프로세스의 부모는 여전히 호출하여 "릴리스"자식 프로세스에 필요 (그리고 그것의 자원) 여기서 waitwaitpid. 그런 다음 자식 프로세스를 "좀비 프로세스"라고합니다. 참조 howtogeek.com/119815
hogliux

9
프로그램의 일부가 충돌하여 프로그램이 정의되지 않은 상태로 남아 있으면 물론 나머지 프로그램에 문제가 발생할 수 있습니다. 단일 스레드 프로그램에서 예외를 부적절하게 처리하는 경우에도 마찬가지입니다. 문제는 스레드와 관련이 없으며 전역 변경 가능 상태이며 예기치 않은 스레드 종료를 올바르게 처리하지 못한다는 것입니다. 당신의 "정말 밝은"동료는 이것에 전적으로 기반을두고 있습니다.
Jim Mischel

9
"첫 번째 컴퓨터 이후로 항상 기계에 유령이있었습니다. 예상치 못한 프로토콜을 형성하기 위해 함께 그룹화 된 임의의 코드 세그먼트 ..."
Chris Laplante

답변:


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에서 좀비 스레드 시나리오에 영향을주지 않으면 서 잠금을 어떻게 활용할 수 있습니까?

내가 방금 한 일을하지 마십시오!

코드가 자체적으로 올바르게 정리되는 한 ( 관리되지 않는 리소스로 작업하는 경우 Safe Handles 또는 동등한 클래스 사용 ), 이상하고 멋진 방법으로 스레드를 중단하지 않는 한 (가장 안전한 방법은 스레드를 죽이는 적이에 - 그들이 일반적으로 자신을 종료하자, 또는 뭔가 간 경우 예외 필요한 경우), 당신이 뭔가 좀비 스레드를 닮은이가는 유일한 방법 통해 매우 (예를 들어 뭔가 CLR에서 잘못) 잘못된.

실제로 좀비 스레드를 만드는 것은 실제로 놀랍게도 어렵습니다 (필자는 C 외부에서 호출하지 말라고 본질적으로 알려주는 함수로 P / 호출해야했습니다). 예를 들어 다음 코드는 실제로 좀비 스레드를 만들지 않습니다.

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
나는 backgroundworker를 사용하여 Excel에서 물건을 저장하고 놀았을 때 항상 모든 리소스를 공개하지는 않았습니다 (방금 디버깅 등을 건너 뛰었 기 때문에). 작업 관리자에서 약 50 개의 Excel 프로세스를 보았습니다. zombieexcelprocesses를 만들었습니까?
Stefan

3
@Justin-+1-훌륭한 답변입니다. 그래도 나는 당신의 ExitThread전화에 약간 회의적입니다 . 분명히 작동하지만 실제 시나리오보다 영리한 트릭처럼 느껴집니다. 내 목표 중 하나는 실수로 .NET 코드로 좀비 스레드를 만들지 않도록해야 할 일을 배우는 것입니다. .NET 코드에서 해당 문제를 일으키는 것으로 알려진 C ++ 코드를 호출하면 원하는 효과가 발생한다는 것을 알았을 것입니다. 당신은 분명히이 물건에 대해 많이 알고 있습니다. 같은 결과를 가진 다른 경우 (아마도 이상하지만 결코 우연히 일어날 수 없을 정도로 이상하지 않음)를 알고 있습니까?
smartcaveman

3
대답은 'C # 4에 있지 않습니다'입니다. 좀비 스레드를 얻기 위해 CLR을 뛰어 넘어야한다면 .Net 문제처럼 보이지 않습니다.
Gusdor

4
@ 스테판 나는 거의 확실히 말하지 않을 것입니다. 나는 당신이 많은 시간을 설명했습니다. Excel 프로세스는 일반 UI를 통해 즉시 액세스 할 수는 없지만 여전히 실행 중이므로 좀비가 아닙니다. GetObject 호출을 통해 검색 할 수 있어야합니다 . Set excelInstance = GetObject(, "Excel.Application")
Daniel

7
"파일이 프로그램이 종료 될 때까지 열린 상태로 유지됩니다 있도록 파일"TEST.TXT "결과 좀비 스레드는에 핸들을 해제하지 않을 것" 올바르지 않습니다. 작은 증거 :`static void Main (string [] args) {new Thread (GcCollect) .Start (); 새로운 Thread (Target) .Start (); Console.ReadLine (); } private static void Target () {using (var file = File.Open ( "test.txt", FileMode.OpenOrCreate)) {ExitThread (0); }} private static void GcCollect () {while (true) {Thread.Sleep (10000); GC.Collect (); }}`
Sinix

46

내 답변을 약간 정리했지만 참조를 위해 아래에 원래 답변을 남겼습니다.

좀비라는 용어에 대해 들어 본 것은 이번이 처음이므로 그 정의를 다음과 같이 가정하겠습니다.

모든 자원을 공개하지 않고 종료 된 스레드

따라서 그 정의가 주어지면 다른 언어 (C / C ++, java)와 마찬가지로 .NET에서 그렇게 할 수 있습니다.

그러나 나는 이것이 .NET에서 스레드 된 미션 크리티컬 코드를 작성하지 않는 좋은 이유라고 생각하지 않습니다. .NET에 대해 결정해야 할 다른 이유가있을 수 있지만 좀비 스레드가 어떻게 든 이해가되지 않기 때문에 .NET을 작성하는 것이 좋습니다. C / C ++에서 좀비 스레드가 가능합니다 (C에서 엉망이되는 것이 훨씬 쉽다고 주장합니다).

결론 사용할 언어를 결정하는 중이라면 성능, 팀 기술, 일정, 기존 앱과의 통합 등과 같은 큰 그림을 고려하는 것이 좋습니다. 물론 좀비 스레드는 고려해야 할 사항입니다. .NET에서 C와 같은 다른 언어와 비교할 때 실제로 실수하기가 너무 어렵 기 때문에 위에서 언급 한 것과 같은 다른 문제로 인해이 문제가 어두워 질 것이라고 생각합니다. 행운을 빕니다!

적절한 스레딩 코드를 작성하지 않으면 원래 답변 좀비 가 존재할 수 있습니다. C / C ++ 및 Java와 같은 다른 언어에서도 마찬가지입니다. 그러나 이것이 .NET에서 스레드 코드를 작성하지 않는 이유는 아닙니다.

다른 언어와 마찬가지로 무언가를 사용하기 전에 가격을 알아야합니다. 또한 잠재적 인 문제를 예측할 수 있도록 후드에서 발생하는 상황을 파악하는 데 도움이됩니다.

어떤 언어를 사용하든 미션 크리티컬 시스템을위한 안정적인 코드를 작성하는 것은 쉽지 않습니다. 그러나 .NET에서 올바르게 수행하는 것은 불가능하지 않습니다. 또한 AFAIK, .NET 스레딩은 C / C ++의 스레딩과 다르지 않으며 일부 .net 관련 구문 (예 : RWL 및 이벤트 클래스의 경량 버전)을 제외하고는 동일한 시스템 호출을 사용하거나 그로부터 작성됩니다.

좀비라는 말을 처음 들었을 때, 당신의 설명에 따르면, 동료는 아마 모든 리소스를 공개하지 않고 종료되는 스레드를 의미했을 것입니다. 교착 상태, 메모리 누수 또는 기타 나쁜 부작용이 발생할 수 있습니다. 이것은 분명히 바람직하지만, 이것 때문에 .NET을 지목하지 가능성 아마 너무 다른 언어로 가능하기 때문에 좋은 생각이 아니다. 나는 심지어 .NET (특히 RAII가없는 C)보다 C / C ++에서 엉망이 쉽지만 많은 중요한 앱이 C / C ++로 작성되었다고 주장하고 싶습니까? 그래서 그것은 실제로 당신의 개인적인 상황에 달려 있습니다. 응용 프로그램에서 모든 속도를 추출하고 가능한 한 베어 메탈에 가깝게 접근하려는 경우 .NET 최고의 솔루션이 아닙니다. 당신이 단단한 예산에 및 / 웹 서비스와 인터페이스 .NET 라이브러리 / 등 기존의 많이 할 경우, .NET이 있을 수 있습니다 좋은 선택.


(1) 막 다른 extern방법을 쳤을 때 후드에서 무슨 일이 일어나고 있는지 알아내는 방법을 잘 모르겠습니다 . 당신이 제안을 가지고 있다면, 나는 그것을 듣고 싶습니다. (2) .NET에서 가능하다는 데 동의합니다. 나는 잠금 장치가있는 가능 믿고 싶지만, 나는 오늘 정당화하기 위해 만족스러운 답을 찾을 아직
smartcaveman

1
@smartcaveman 의미하는 locking것이 lock키워드라면 실행을 직렬화하기 때문에 아마도 아닙니다. 처리량을 최대화하려면 코드의 특성에 따라 올바른 구성을 사용해야합니다. pthreads / boost / thread pools / whatever를 사용하여 c / c ++ / java / what에서 안정적인 코드를 작성할 수 있다면 C #으로 작성할 수도 있습니다. 그러나 라이브러리를 사용하여 어떤 언어로도 신뢰할 수있는 코드를 작성할 수 없다면 C #으로 작성하는 것이 달라지지 않을 것입니다.
Jerahmeel

@smartcaveman은 후드 아래에있는 것을 파악하는 데 도움이되며 Google은 힙을 지원하며 문제가 웹에서 찾기에 너무 이국적 인 경우 반사기가 매우 편리합니다. 그러나 스레딩 클래스의 경우 MSDN 설명서가 매우 유용합니다. 그리고 많은 것은 C에서 사용하는 동일한 시스템 호출에 대한 래퍼 일뿐입니다.
Jerahmeel

1
@ smartcaveman은 전혀 아니 었습니다. 그렇게 됐다면 미안 해요 내가 말하고 싶은 것은 중요한 응용 프로그램을 작성할 때 .NET을 너무 빨리 작성해서는 안된다는 것입니다. 물론, 당신이 물건을 할 수있는 어쩌면 (나는 완전히 다른 언어로 일어날 수있는 관리되지 않는 리소스를 해제하지 않았다 단지 스레드 생각 : 좀비 스레드보다 더 많은 stackoverflow.com/questions/14268080/...이 )지만, 다시 말해 .NET이 실행 가능한 솔루션이 아니라는 의미는 아닙니다.
Jerahmeel

2
.NET이 나쁜 기술이라고 생각하지 않습니다. 실제로 내 기본 개발 프레임 워크입니다. 그러나 이로 인해 취약한 결함을 이해하는 것이 중요하다고 생각합니다. 기본적으로 .NET을 싱글 링하고 있지만 마음에 들지 않기 때문에 좋아하지 않기 때문입니다. (그리고 걱정 형제는, I +를 1 - 에드 없음)
smartcaveman

26

현재 내 답변의 대부분은 아래 의견에 의해 수정되었습니다. 의견의 정보가 독자에게 가치가 있기 때문에 평판 포인트가 필요하기 때문에 답변을 삭제하지 않습니다 .

Immortal Blue는 .NET 2.0 이상에서 finally블록이 스레드 중단에 영향을받지 않는다고 지적했습니다 . Andreas Niedermair의 의견에 따르면 실제 좀비 스레드는 아니지만 다음 예제에서는 스레드 중단으로 인해 문제가 발생할 수있는 방법을 보여줍니다.

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때 a ThreadAbortException가 그런 식으로 발사 되면 여전히 실행됩니다 .

다음 정보는 .NET 1 및 .NET 1.1에만 유효합니다.

lock() { }블록 내부에서 다른 예외가 발생 ThreadAbortException하고 finally블록을 실행하려고 할 때 정확하게 도착 하면 잠금이 해제되지 않습니다. 언급했듯이 lock() { }블록은 다음과 같이 컴파일됩니다.

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

Thread.Abort()생성 된 finally블록 내부에서 다른 스레드가 호출 되면 잠금이 해제되지 않을 수 있습니다.


2
당신이 이야기하고 lock()있지만 이것의 사용법을 볼 수 없습니다 ... 그래서-어떻게 연결되어 있습니까? 이의 "잘못"사용 인 Monitor.EnterMonitor.Exit(의 사용을 결여 try하고 finally)
안드레아스 Niedermair

4
이 단순히 잘못된 사용법이다 - 좀비 스레드 것을 호출 할 것이다 Monitor.EnterMonitor.Exit의 적절한 사용없이 try하고 finally- 당신의 시나리오에 중단 될 수 있습니다 다른 스레드를 잠글 것, 어쨌든 _lock반드시 좀비 스레드 -, 그래서 교착 상태 시나리오있다 ... 또한 잠금을 해제 Main하지는 않지만 ... 좀비 스레드 대신 교착 상태에 대해 OP가 잠금을 해제하고 있습니다 :)
Andreas Niedermair

1
@AndreasNiedermair 아마도 좀비 스레드의 정의가 내가 생각한 것이 아닙니다. 아마도 우리는 이것을 "실행을 종료했지만 모든 리소스를 해제하지 않은 스레드"라고 부를 수 있습니다. 과제를 삭제하고 수행하려고했지만 OP의 시나리오와 유사하게 답변을 유지하려고합니다.
C.Evenhuis

2
여기에 위반이 없습니다! 실제로 당신의 대답은 방금 생각했습니다 :) OP가 릴리스되지 않은 잠금에 대해 명시 적으로 이야기하고 있기 때문에 그의 동료가 교착 상태에 대해 이야기했다고 생각합니다. 잠금은 스레드에 바인딩 된 실제 리소스가 아니기 때문에 ( 모범 사례에 집착하고 사용하여, 따라서 어떤 "좀비"스레드는 피할 수 - 그것은) 노나 ... 공유되는 lock적절한 또는 try/ finally-usage
안드레아스 Niedermair

1
@ C.Evenhuis-내 정의가 정확한지 확실하지 않습니다. 내가 질문하는 이유 중 하나는 이것을 정리하는 것입니다. 나는이 개념이 C / C ++에서 크게 언급되었다고 생각한다
smartcaveman

24

이것은 Zombie 스레드에 관한 것이 아니라 Effective C # 책에는 IDisposable 구현에 대한 섹션 (항목 17)이 있습니다.

책 자체를 읽는 것이 좋지만, IDisposable을 구현하거나 Desctructor를 포함하는 클래스가 있으면 리소스를 공개하는 것이 유일한 방법입니다. 여기서 다른 작업을 수행하면 객체가 가비지 수집되지 않지만 어떤 방식으로도 액세스 할 수 없게 될 가능성이 있습니다.

다음과 유사한 예를 제공합니다.

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

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

이 객체의 소멸자가 호출되면 자체에 대한 참조가 전체 목록에 배치됩니다. 즉, 프로그램 수명 동안 살아 있고 메모리에 남아 있지만 액세스 할 수는 없습니다. 이는 리소스 (특히 관리되지 않는 리소스)가 완전히 해제되지 않아 모든 종류의 잠재적 인 문제가 발생할 수 있음을 의미 할 수 있습니다.

보다 완전한 예는 다음과 같습니다. foreach 루프에 도달 할 때마다 언데드 목록에 각각 이미지를 포함하는 150 개의 객체가 있지만 이미지가 GC로 지정되어 있고 사용하려고하면 예외가 발생합니다. 이 예제에서는 이미지를 저장하려고 시도하거나 높이 및 너비와 같은 치수를 보려고 할 때 이미지로 무언가를 시도 할 때 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 12

4
확실히 그게 문제가되지는 않습니다 IDisposable. 종료 자 (소멸자)와 관련이 있지만 IDisposable객체를 종료 자 대기열로 보내지 않고이 좀비 시나리오에 위험을 초래하지는 않습니다. 이 경고는 종료 자와 관련이 있으며 Dispose 메서드를 호출 할 수 있습니다. 종료자가 IDisposable없는 유형에 사용되는 예가 있습니다 . 감정은 리소스 정리에 대한 것이지만 사소한 리소스 정리가 될 수 있습니다. RX IDisposable는 구독 정리에 유효하게 사용 되며 다른 다운 스트림 자원을 호출 할 수 있습니다. (나는 둘 중 하나를 공감하지 않았다 ...)
James World

21

로드가 많은 중요한 시스템에서는 성능 향상으로 인해 잠금없는 코드를 작성하는 것이 좋습니다. LMAX 와 같은 것을 살펴보고 이것이 어떻게 큰 토론을 위해 "기계적 동정"을 활용하는지 살펴보십시오 . 좀비 스레드가 걱정 되십니까? 나는 그것이 다림질해야 할 버그 일뿐 아니라 사용하지 않을 충분한 이유가 아닌 가장자리 케이스라고 생각합니다 lock.

친구가 그냥 화려하고 이국적인 용어를 모호하게하는 그의 지식을 과시하는 것처럼 들립니다! Microsoft UK에서 성능 랩을 실행하는 동안 항상 .NET에서이 문제의 인스턴스를 보지 못했습니다.


2
다양한 경험을 통해 다른 버그에 대해 편집증이 생길 수 있다고 생각합니다. 그는 그것을 설명하면서 극단적 인 에지 사건을 인정하지만, 정말 가장자리의 경우가 아닌 절대의 경우의 경우, 나는 적어도 좀 더 잘 이해하고 싶습니다 - 귀하의 의견을 주셔서 감사합니다
smartcaveman

1
그럴 수 있지. 나는 당신이 그 lock진술 에 대해 불균형 적으로 걱정하기를 원하지 않을 것입니다 !
제임스 월드

1
이 문제에 대해 더 깊이 이해하고 있다면 걱정할 필요가 없습니다.
smartcaveman

4
나는 너무 많은 스레드 FUD를 제거하려고 노력했기 때문에 공감했다. Lock-FUD는 다음을 처리하기 위해 더 많은 작업을 수행 할 것입니다.
Martin James

3
그렇습니다. 일반 및 특정 측면에서 모두 가능합니다. 올바른 잠금없는 코드를 작성하는 것은 프로그래밍만큼 어렵습니다. 대다수의 경우에 대한 나의 경험에서, (상대적으로) 이해하기 쉬운 큰 뚱뚱한 코스 lock블록은 괜찮습니다. 필요한 것을 알 때까지 성능 최적화를 위해 복잡성을 도입하는 것을 피하고 싶습니다.
제임스 월드

3

1. 여기서 설명한 것보다 "좀비 스레드"에 대한 명확한 정의가 있습니까?

"Zombie Threads"가 존재한다는 데 동의합니다. 쓰레드에서 발생하지 않고 완전히 죽지 않은 리소스가 남은 스레드를 나타내는 용어이므로 "좀비"라는 이름입니다. 이 추천에 대한 설명은 돈에 꽤 맞습니다!

2. 좀비 스레드가 .NET에서 발생할 수 있습니까? (왜 왜 안돼?)

그렇습니다. 참고로 실제로 Windows에서는 "좀비"라고합니다. MSDN은 죽은 프로세스 / 스레드에 "좀비"라는 단어를 사용합니다.

자주 일어나는 것은 또 다른 이야기이며, 스레드 잠금과 같은 코딩 기술과 관행에 달려 있으며 잠시 동안 해본 적이 있습니다. 나는 당신에게 일어나는 시나리오에 대해 걱정하지 않을 것입니다.

그리고 예, @KevinPanko가 주석에서 올바르게 언급했듯이 "Zombie Threads"는 Unix에서 왔기 때문에 XCode-ObjectiveC에서 사용되며 "NSZombie"라고하며 디버깅에 사용됩니다. 그것은 거의 같은 방식으로 작동합니다 ... 유일한 차이점은 코드에서 잠재적 인 문제 일 수있는 "좀비 스레드"대신 디버깅을 위해 "좀비 객체"가된다는 것입니다.


1
그러나 MSDN에서 좀비를 사용 하는 방식은이 질문에서 사용하는 방식과 매우 다릅니다.
벤 Voigt

1
예, 동의합니다.하지만 MSDN조차도 스레드가 죽었을 때 좀비 스레드라고 말합니다. 실제로 발생할 수 있습니다.
SH

4
물론, 스레드 보유 핸들이 자원을 종료 할 때 핸들이 아니라 스레드에 대한 핸들을 잡고있는 다른 코드를 참조하고 있습니다. 문제의 정의에 동의 한 첫 번째 문장이 잘못되었습니다.
벤 Voigt

1
아 당신의 요점을 참조하십시오. 솔직히 나는 그것을 알아 차리지 못했습니다. 나는 그 정의가 어떻게 일어나는지에 관계없이 그 정의가 존재한다는 점에 초점을 맞추고 있었다. 정의는 스레드가 수행되는 방식이 아니라 스레드에 발생하기 때문에 존재한다는 것을 기억하십시오.
SH

0

좀비 실을 쉽게 만들 수 있습니다.

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

스레드 핸들이 누출됩니다 (for Join()). 우리가 관리되는 세계에서 우려하는 한 또 다른 메모리 누수입니다.

이제 실제로 잠금을 유지하는 방식으로 실을 죽이는 것은 후면의 고통이지만 가능합니다. 다른 사람 ExitThread()이 일을 해요. 그가 찾은 것처럼 파일 핸들은 gc에 의해 정리되었지만 lock객체 주위는 그렇지 않습니다. 그러나 왜 그렇게하겠습니까?

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.