首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >0x80010100:系统调用失败“异常,ContextSwitchDeadlock

0x80010100:系统调用失败“异常,ContextSwitchDeadlock
EN

Stack Overflow用户
提问于 2012-02-21 19:28:45
回答 1查看 6.5K关注 0票数 0

长话短说:在使用COM inproc-server (dll)的C#应用程序中,我遇到了"0x80010100:系统调用失败“异常,在调试模式下也遇到了ContextSwitchDeadlock异常。

现在更详细地说:

1) C# app初始化STA,创建一个COM对象(注册为“公寓”);然后在订阅它的连接点,并开始使用该对象。

2)在某些阶段,COM对象生成许多事件,将在同一单元中创建的COM对象的一个非常大的集合作为参数传递。

3) C#端的事件处理程序处理上述集合,偶尔调用对象的一些方法。在某些阶段,后一种调用开始失败,出现上述异常。

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

代码语言:javascript
复制
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服务器的其他部分发布到此窗口:

代码语言:javascript
复制
void post(const Functor &func)
{
  Functor *f = new Functor(func);
  PostMessage(hWind_, AM_FUNCTOR, 0, reinterpret_cast<LPARAM>(f));
}

这些事件是与实际参数绑定的标准ATL CP实现,它们可以归结为以下内容:

代码语言:javascript
复制
pConnection->Invoke(id, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, &varResult, NULL, NULL);

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

代码语言:javascript
复制
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“调用。第一个进入C#托管代码,它试图重新进入非托管代码,即同一单元。通常,这是允许的,而且我们经常这样做。什么时候,在什么情况下,它会失败?

谢谢。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-02-21 23:31:38

这应该适用于多套公寓,但前提是:

  • 只有一个线程响应外部事件,如网络流量、计时器、发送的消息等。
  • 其他线程只处理COM请求(即使它们在处理过程中回调到主线程)。

  • 两个线程队列都不会填满,从而阻止COM与线程通信。

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

您所描述的是一个典型的死锁--两个独立的线程,每个线程都在等待另一个线程。这就是我期望在不同线程上使用C#和COM端运行设计时会发生的事情。

如果所有的对象都在同一个线程上,并且隐藏窗口在那个线程上,那么你应该没问题,所以我认为你需要检查这一点。(显然,这包括由COM端创建并传递给C#端的任何其他对象。)

您可以尝试通过在调试器中按"pause“并检查每个线程中有哪些代码来调试它(如果您看到RPCRT*.DLL,这意味着您正在查看代理)。或者,您可以从C#和COM端的不同临界点以及您的WndProc中DebugPrint当前线程ID -它们都应该是相同的。

其次:它应该与多线程一起工作,前提是只有一个线程生成工作项,而另一个线程只做响应调用的宿主COM对象(即不从计时器、网络流量、发布的消息等生成调用),在这种情况下,可能是线程队列已满,COM无法响应调用。

您应该使用由临界区保护的双队列,而不是使用线程队列。

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

每个消息队列最多只能发送10,000条消息。这个限制应该足够大。如果您的应用程序超出了限制,则应对其进行重新设计,以避免消耗太多系统资源。

您可以维护一个队列上/队列外的项目计数器,以查看这是否是问题所在。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9376773

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档