0x80010100:系统调用失败“异常,ContextSwitchDeadlock [英] 0x80010100: System call failed" exception, ContextSwitchDeadlock

查看:1042
本文介绍了0x80010100:系统调用失败“异常,ContextSwitchDeadlock的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

长故事:在与COM inproc-server(dll)工作的C#应用​​程序中,我遇到0x80010100:系统调用失败异常,并且在调试模式下还会出现ContextSwitchDeadlock异常。



现在更详细的:



1)C#应用程序初始化STA,创建一个COM对象然后在订阅其连接点,并开始使用对象。



2)在某些阶段,COM对象生成很多事件,作为参数传递



3)C#侧的事件处理程序处理上面的集合,偶尔调用一些方法对象。



在COM端,公寓使用一个隐藏窗口,其winproc如下所示:

  typedef std :: function< void(void)>函子; 
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服务器的其他部分发布到此窗口: / p>

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

事件是与实际params绑定的标准ATL CP实现,下面这样:

  pConnection-> Invoke(id,IID_NULL,LOCALE_USER_DEFAULT,DISPATCH_METHOD,& params,& varResult,NULL,NULL); 

在C#中,处理程序如下所示:

  private void onEvent(IMyCollection objs)
{
int len = objs.Count; //通常10000 - 25000
foreach(IMyObj obj in objs)
{
//以下调用失败,0x80010100
int id = obj.id;
string name = obj.name;
// etc ...
}
}

=================



因此,上述问题的发生只是因为公寓的消息队列太加载它试图提供的事件?



假设消息队列有两个顺序的事件,它们被评估为onEvent调用。第一个进入C#托管代码,尝试重新输入非托管代码,同一公寓。通常,这是允许的,我们这样做很多。什么时候可以失败?



谢谢。

解决方案

这应该可以工作,即使有多个公寓提供:




  • 只有一个线程响应外部事件,如网络流量,


  • $ b
  • 其他线程仅服务COM请求(即使他们在处理期间回调到主线程)。
    $ b

    AND




    • 两个线程队列都未满,阻止COM与线程通信。 >


    首先:
    看起来一些对象与其他对象不在同一公寓。您确定所有对象都在STA中创建吗?



    您正在描述的是一个经典的死锁 - 两个独立的线程,每个线程都在等待另一个线程。这是我期望发生与设计操作与C#和COM侧在不同的线程。



    如果所有对象在同一个线程上,以及该线程上的隐藏窗口,您应该可以你需要检查。 (显然这包括由COM端创建并传递给C#端的任何其他对象。)



    您可以尝试通过按调试器和检查每个线程中的什么代码(如果你看到RPCRT * .DLL这意味着你正在看一个代理)。或者,您可以从C#和COM端的各个关键点DebugPrint当前线程ID和您的WndProc - 它们应该是相同的。



    其次: / strong>它应该使用多线程,只有一个线程生成工作项,而另一个只负责响应调用的COM对象(即不产生来自计时器,网络流量,发布的消息等的调用) ),在这种情况下可能是线程队列已满并且COM无法响应调用。



    而不是使用线程队列,您应该使用deque保护




    您可以维护项目开/这是问题。



    Long story short: in a C# application that works with COM inproc-server (dll), I encounter "0x80010100: System call failed" exception, and in debug mode also ContextSwitchDeadlock exception.

    Now more in details:

    1) C# app initializes STA, creates a COM object (registered as "Apartment"); then in subscribes to its connection-point, and begins working with the object.

    2) At some stage the COM object generates a lot of events, passing as an argument a very big collection of COM objects, which are created in the same apartment.

    3) The event-handler on C# side processes the above collection, occasionally calling some methods of the objects. At some stage the latter calls begin to fail with the above exceptions.

    On the COM side the apartment uses a hidden window whose winproc looks like this:

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

    The events are posted to this window from other parts of the COM server:

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

    The events are standard ATL CP implementations bound with the actual params, and they boil down to something like this:

    pConnection->Invoke(id, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, &varResult, NULL, NULL);
    

    In C# the handler looks like this:

    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...
      }
    }
    

    ==================

    So, can the above problem happen just because the message-queue of the apartment is too loaded with the events it tries to deliver? Or the message loop should be totally blocked to cause such a behaviour?

    Lets assume that the message-queue has 2 sequential events that evaluate to "onEvent" call. The first one enters C# managed code, which attempts to re-enter the unmanaged code, the same apartment. Usually, this is allowed, and we do this a lot. When, under what circumstances can it fail?

    Thanks.

    解决方案

    This ought to work even with multiple apartments provided that:

    • Only one of the threads responds to external events such as network traffic, timers, posted messages etc.
    • Other threads only service COM requests (even if they call back to the main thread during the processing).

    AND

    • neither thread queue ever gets full, preventing COM from communicating with the thread.

    Firstly: It looks like some objects are not in the same apartment as other objects. Are you sure that all objects are being created in the STA?

    What you are describing is a classic deadlock - two independent threads, each waiting on the other. That is what I would expect to occur with that design operating with the C# and COM sides on different threads.

    You should be OK if all the objects are on the same thread, as well as the hidden window being on that thread, so I think you need to check that. (Obviously this includes any other objects which are created by the COM side and passed over to the C# side.)

    You could try debugging this by pressing "pause" in the debugger and checking what code was in each thread (if you see RPCRT*.DLL this means you are looking at a proxy). Alternately you could DebugPrint the current thread ID from various critical points in both C# and COM sides and your WndProc - they should all be the same.

    Secondly: it ought to work with multiple threads provided that only one of the threads generates work items, and the other does nothing but host COM objects which respond to calls (i.e. doesn't generate calls from timers, network traffic, posted messages etc), in this case it may be that the thread queue is full and COM cannot reply to a call.

    Instead of using the thread queue, you should use a deque protected by a critical section.

    You might maintain a counter of items on/off the queue to see if this is the issue.

    这篇关于0x80010100:系统调用失败“异常,ContextSwitchDeadlock的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆