2014-11-18 2 views
2

개인, 로컬 메시지 큐 (MSMQ)를 처리하는 Windows 서비스가 있습니다. 시작될 때 큐에 PeekCompleted에 대한 이벤트 처리기를 등록한 다음 비동기 BeginPeek()을 호출하여 메시지가 도착하기를 기다립니다.BeginPeek을 사용한 후에 EndPeek에 전화해야합니까?

protected override void OnStart(string[] args) 
{ 
    if (String.IsNullOrWhiteSpace(args[0])) 
     return; 

    queue = new MessageQueue(args[0]); 
    queue.Formatter = new BinaryMessageFormatter(); 
    queue.PeekCompleted += new PeekCompletedEventHandler(OnPeekCompleted); 

    queue.BeginPeek(); 
} 

일단 메시지가 도착하면, 분명히 그 메시지를 처리하는 것이 목표입니다. 내 코드는 현재 트랜잭션 내에 포함 된 메시지를 가져 오는 queue.Receive() 메서드를 가지고 있으므로 처리 중에 오류가 발생하면 메시지가 대기열에 다시 저장됩니다. BeginPeek()이 다시 호출되어 사이클을 다시 시작합니다.

private static void OnPeekCompleted(Object source, PeekCompletedEventArgs asyncResult) 
{ 
    try 
    { 
     MessageQueue q = (MessageQueue)source; 

     using (MessageQueueTransaction trans = new MessageQueueTransaction()) 
     { 
      trans.Begin(); 

      Message msg = q.Receive(trans); 
      ProcessMessage(msg); 

      trans.Commit(); 
     } 

     // Restart the asynchronous peek operation. 
     q.BeginPeek(); 
    } 
    catch (MessageQueueException qEx) 
    { 
     // TODO: Walk it off. 
    } 
    return; 
} 

마 내가 어떤 시점에서, 큐에 EndPeek()를 호출 할 필요가?

this question과 같은 메모리 누출을 피할 수 있습니까? 나는 그럴 필요가 없다고 확신하지만 문서화는 그다지 명확하지 않다. 그것은 단지 그것을 끝내지 않고 무언가를 '시작'하는 것을 100 % 올바르게 느끼지 못한다. :)

Btw : 줄을 Message msg = q.EndPeek(asyncResult.AsyncResult)으로 바꿀 수 있는데, 나는 똑같이 메시지를 가져 오지만, 메시지를 가져 오지는 않는다. 대기열의 메시지

+0

'.EndPeek() '을 호출하지 않는 이유가 있습니까? '.EndPeek()'의 결과를 필요로하지 않는다면, 그것을 버릴 수는 있지만, 전혀 호출하지 않는 것은 거의 나쁜 생각입니다. 여러분은 본질적으로'.BeginPeek()'에 뱅킹하고 있습니다. '.EndPeek()'이 해제해야하는 관리되지 않는 리소스를 할당합니다. 그것이 사실 일지라도, 누가 다음 릴리스가 그 가정을 깨뜨리지 않을 것이라고 말합니까? –

+0

사이드 노트 : pleinolijf, 내 게시물이 "내 코드가 틀린 것처럼 보입니다. 신뢰할 수있는 기회가 될 수 있습니다."와 같이 읽습니다. 개인적으로 코드의 정확성에 관계없이 그렇게하지는 않을 것입니다. 미래의 모든 독자가 EndXXXX 코드를 찾거나 수정하는 데 낭비되는 시간이 낭비 될 것입니다. –

+0

공정한 점수, 둘 다. 그리고 그것은 본질적으로 제가 요구하는 것입니다 : EndPeek에 전화하지 않는 것이 안전할까요? BeginPeek은 실제로 어떤 자원을 할당합니까? 분명히 나에게 불명확 한 것은, 비록 분명히 방법의 이름이 그것을 암시하지만. 내가 찾고있는 건 사실이 아니라 가정이다. – pleinolijf

답변

10

짧은 대답 ("아니오")이 오도 될 수 있으므로이 질문에 대한 적절한 대답은 약간의 노력이 필요합니다.

API 설명이 명시 적으로 일 경우이라고 말하면 BeginPeek()을 호출 할 때마다 EndPeek()으로 전화해야합니까? 아니 어떤 주제에 내가 찾을 수 있고,뿐만 아니라, 반대 here이 상태로 나타납니다

, BeginPeek를 사용하는 비동기 작업의 을 결과를 처리하는 이벤트 핸들러를 만들려면과와 연결하여 이벤트 대리인. BeginPeek은 비동기 피크 작동을 시작합니다. MessageQueue은 메시지가 대기열에 도착할 때 PeekCompleted 이벤트 발생시 통보됩니다. 그러면 MessageQueue또는을 호출하여 을 검색하여 PeekCompletedEventArgs을 사용하여 메시지에 액세스하면 에 메시지에 액세스 할 수 있습니다.

(강조 광산.) 이것은 당신이 .EndPeek()를 사용하거나 직접 .EndPeek()를 호출 할 의무와 이벤트 인수에서 메시지를받을 수 있습니다 말할 것 같다.

올바르게 작동하도록하려면 .EndPeek()으로 전화하는 구현 의무가 있습니까? 최소한 .NET 4.0의 System.Messaging 구현의 경우 대답은 '아니오'입니다. .BeginPeek()을 호출하면 비동기 작업이 할당되고 완료를 위해 콜백이 등록됩니다. 이 작업과 관련된 관리되지 않는 리소스는이 콜백에서 부분적으로 정리 된 다음 호출 된 이벤트 처리기입니다. .EndPeek()은 실제로 정리를 수행하지 않습니다. 아직 완료되지 않았 으면 작업이 완료 될 때까지 대기하고 오류를 확인한 다음 메시지를 반환합니다. 따라서 .EndPeek()에 전화하거나 이벤트 args에서 메시지에 액세스하거나 아무것도하지 않는 것이 사실입니다. 모든 작업이 제대로 수행되지 않습니다.

가난하고 예 - "부분적으로 정리했다"는 것에 유의하십시오. MessageQueue의 구현은 모든 비동기 작업에 대해 ManualResetEvent을 할당하지만 문제를 일으키지 않습니다. 가비지 수집기를 완전히 비워 두지 않습니다. .NET 개발자는 흔히 흉내낼 수 있지만 Microsoft 자체 개발자는 아닙니다. 어느 쪽도 완벽하지 않습니다. this question에 설명 된 OverlappedData 누출이 여전히 관련성이 있는지 또는 출처에서 즉시 명백한 지 여부는 테스트하지 않았지만 놀라지 않을 것입니다.

API에는 구현시 비동기 작업에 대해 설정된 .Begin...()/.End...() 패턴을 따르지 않지만 중간에 이벤트 처리기가 도입되어 이상한 하이브리드를 생성한다는 점이 눈에 띄게 나타납니다. 다른 곳에서는 결코 볼 수 없다. 그런 다음 Message 클래스를 Component에서 상속하는 매우 모호한 결정이 있습니다.이 인스턴스는 모든 인스턴스에 상당한 오버 헤드를 추가하고 언제 어떻게 처리해야하는지에 대한 의문을 제기합니다. Microsoft의 최선의 작업이 아닙니다.

지금은 .EndPeek()에 "의무"가 없다는 뜻입니까? 그렇습니다. 부름을 부르거나 부르지 않으면 자원 정화 또는 정확성과 관련하여 기능적 차이가 없습니다. 하지만 모든 말로, 내 충고는 여전히 어쨌든라고 부릅니다. 왜? 비동기 작업 패턴이 다른 .NET 클래스에서 작동하는 방식을 잘 알고있는 사용자는 호출이있을 것으로 예상하고 리소스 누설로 이어질 수있는 버그처럼 보입니다. 응용 프로그램에 문제가있는 경우 그러한 사람은 그렇지 않은 "문제 코드"를 보면서 쓸데없는 노력을 합리적으로 할 수 있습니다. .EndPeek()에 대한 호출이 나머지 기계류와 비교할 때 무시할 수있는 오버 헤드를 가지고 있다고 가정하면, 프로그래머의 비용 절감은 비용을 보충하는 것 이상입니다. 가능한 대안은 대신에 .EndPeek()을 호출하지 않는 이유를 설명하는 주석을 삽입하는 것입니다.하지만 모든 가능성이 있기 때문에이를 호출하는 것보다 더 많은 프로그래머 사이클이 필요합니다.

이론적으로 API 호출의 의미가 나중에 변경되어 .EndPeek() 호출이 필요하게 될 수도 있습니다. 실제로 이것은 마이크로 소프트가 전통적으로 이와 같은 변화를 주저하고 있기 때문에 일어나지 않을 것입니다. (이전에 합리적으로 .EndPeek()이라고 부르지 않은 코드는 작동을 멈 춥니 다.) 기존의 구현은 이미 기존의 실행에 위배됩니다.

+0

+1 훌륭한 추론과 노력에 감사드립니다.) – pleinolijf

관련 문제