2012-02-21 10 views
0

짧은 이야기 : COM inproc-server (dll)에서 작동하는 C# 응용 프로그램에서"0x80010100 : System call failed "예외가 발생하고 디버그 모드에서도 ContextSwitchDeadlock 예외가 발생합니다.0x80010100 : System call failed "예외, ContextSwitchDeadlock

세부 사항에 이제 더 :.

1) C#을 응용 프로그램은 "아파트"로 등록 된 COM 객체를()를 작성, STA를 초기화 한 후 그 연결 지점 구독에, 및 오브젝트 작업 시작을

2) 어떤 단계에서 COM 개체는 COM 개체의 매우 큰 컬렉션을 인수로 전달하여 많은 이벤트를 생성합니다 같은 아파트에 만들어져 있습니다.

3) C# 측 이벤트 핸들러는 위의 콜렉션을 처리하며 때로는 오브젝트의 일부 메소드를 호출합니다. 어떤 단계에서 후자의 호출은 위의 예외로 실패하기 시작합니다. 는 COM 측면에서

아파트는 그 winproc 다음과 같습니다 숨겨진 창을 사용

typedef std::function<void(void)> Functor; 
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 
{ 
    switch(msg) 
    { 
    case AM_FUNCTOR: 
    { 
     Functor *f = reinterpret_cast<Functor *>(lParam); 
     (*f)(); 
     delete f; 
    } 
    break; 
    case WM_CLOSE: 
     DestroyWindow(hwnd); 
    break; 
    default: 
     return DefWindowProc(hwnd, msg, wParam, lParam); 
    } 
    return 0; 
} 

이벤트는 COM 서버의 다른 부분에서이 창에 게시됩니다

void post(const Functor &func) 
{ 
    Functor *f = new Functor(func); 
    PostMessage(hWind_, AM_FUNCTOR, 0, reinterpret_cast<LPARAM>(f)); 
} 

이벤트는 실제 매개 변수와 바인딩 된 표준 ATL CP 구현이며 다음과 같이 바뀝니다.

pConnection->Invoke(id, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, &varResult, NULL, NULL); 
C#에서 5,

핸들러는 다음과 같습니다

private void onEvent(IMyCollection objs) 
{ 
    int len = objs.Count; // usually 10000 - 25000 
    foreach (IMyObj obj in objs) 
    { 
    // some of the following calls fail with 0x80010100 
    int id = obj.id; 
    string name = obj.name; 
    // etc... 
    } 
} 

================== 그래서

, 위의 문제는 단지 메시지 때문에 발생할 수 아파트의 큐에 배달하려고하는 이벤트가 너무 많이로드되어 있습니까? 또는 이러한 동작을 발생 시키려면 메시지 루프가 완전히 차단되어야합니까?

메시지 대기열에는 "onEvent"호출로 평가되는 2 개의 순차적 이벤트가 있다고 가정합니다. 첫 번째 코드는 C# 관리 코드를 입력합니다.이 코드는 동일한 아파트의 관리되지 않는 코드를 다시 입력하려고 시도합니다. 일반적으로 이것은 허용되며 많은 작업을 수행합니다. 언제 어떤 상황에서 실패 할 수 있습니까?

감사합니다.

+1

이 오류는 가장 일반적으로 COM 서버가 충돌하고 AccessViolation이 발생하여 발생합니다. 서버를 디버그해야합니다. –

+0

@Hans Passant 앞서 언급했듯이 서버는 dll이며 "디버그 비 관리 코드"를 사용하도록 설정하여 C# 응용 프로그램과 함께 디버깅합니다. 그리고 안돼, 아무것도 DLL 내부 충돌. –

답변

2

이 있음을 제공하는 여러 아파트로도 작동한다고 : 스레드의

  • 하나는 등 네트워크 트래픽, 타이머, 게시 된 메시지와 같은 외부 이벤트에 응답
  • 다른 스레드에만 서비스 COM 요청 (처리 중에 메인 쓰레드를 다시 호출하더라도).

  • 도 스레드 큐 이제까지 스레드와 통신 COM을 방지, 전체 가져옵니다. 첫째

: 일부 개체가 다른 개체와 같은 아파트에없는 것처럼 같습니다.모든 개체가 STA에서 만들어지고 있습니까?

당신이 설명하는 것은 고전적인 교착 상태입니다. 두 개의 독립적 인 스레드가 각각 다른 스레드를 기다리고 있습니다. 그게 내가 다른 스레드에서 C# 및 COM 쪽에서 작동하는 디자인에서 발생할 것으로 예상되는 것입니다.

모두 개체가 동일한 스레드뿐만 아니라 숨겨진 창이 해당 스레드에있는 경우 확인해야합니다. 그래서 당신이 확인해야한다고 생각합니다. (분명히 이것은 COM 측에 의해 생성되고 C# 측에 전달 된 다른 객체를 포함합니다.)

디버거에서 "일시 중지"를 누르고 각 스레드에 어떤 코드가 있는지 검사하여 디버깅을 시도 할 수 있습니다. if 당신은 RPCRT * .DLL이 당신이 프록시를보고 있다는 것을 의미합니다 참조). 또는 C# 및 COM 측면과 WndProc의 다양한 중요 지점에서 현재 스레드 ID를 DebugPrint 할 수 있습니다. 모두 동일해야합니다.

둘째 : 스레드 중 하나만 작업 항목을 생성하고 다른 하나는 호출에 응답하는 COM 개체를 호스트하는 것 외에는 여러 스레드에서 작동해야합니다 (예 : 타이머, 네트워크 트래픽, 게시 된 메시지 등)이 경우 스레드 대기열이 가득 차서 COM이 호출에 응답 할 수 없습니다.

스레드 대기열을 사용하는 대신 중요 섹션으로 보호 된 비 큐를 사용해야합니다.

  • http://msdn.microsoft.com/en-us/library/windows/desktop/ms644944(v=vs.85).aspx

      는 메시지 큐 10,000 게시 된 메시지의 제한이 있습니다. 이 한계는 충분히 커야합니다. 응용 프로그램이 제한을 초과하면 너무 많은 시스템 자원을 사용하지 않도록 다시 설계해야합니다.
    대기열에서 항목의 카운터를 유지 관리하여 문제가되는지 확인할 수 있습니다.

  • +0

    자세한 답변을 보내 주셔서 감사합니다. 분명히 교착 상태 나 메시지 대기열 오버플로 (> 10K 메시지)가있는 것 같지 않지만이 지점을보다 철저하게 다시 점검 할 것입니다. –

    +0

    당신이 옳았다는 것은 메시지 대기열 오버 플로우였습니다. 오버플로가 된 후에도 COM 메시지는 확실히 아파트에서 처리 할 수 ​​없었습니다. –