Question

Pour faire court: dans une application C # qui fonctionne avec Com inProc-Server (DLL), je rencontre "0x80010100: l'appel système a échoué" Exception, et en mode de débogage également ContextSwitchDeadlock Exception.

Maintenant plus en détail:

1) C # L'application initialise STA, crée un objet COM (enregistré comme "appartement"); Ensuite, dans l'abonnement à son point de connexion, et commence à travailler avec l'objet.

2) À un moment donné, l'objet COM génère beaucoup d'événements, passant comme argument une très grande collection d'objets com, qui sont créés dans le même appartement.

3) Le manteau d'événement sur C # traite la collection ci-dessus, appelant parfois certaines méthodes des objets. À un moment donné, ces derniers appels commencent à échouer avec les exceptions ci-dessus.

Du côté com, l'appartement utilise une fenêtre cachée dont WinProc ressemble à ceci:

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

Les événements sont publiés dans cette fenêtre à partir d'autres parties du serveur COM:

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

Les événements sont des implémentations ATL CP standard liés aux paramètres réels, et ils se résument à quelque chose comme ceci:

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

En C #, le gestionnaire ressemble à ceci:

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

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

Alors, le problème ci-dessus peut-il se produire simplement parce que la fibre de message de l'appartement est trop chargée des événements qu'il essaie de livrer? Ou la boucle de message doit être totalement bloquée pour provoquer un tel comportement?

Supposons que la file de message a 2 événements séquentiels qui évaluent à l'appel "Onevent". Le premier entre dans le code géré C #, qui tente de réintégrer le code non géré, le même appartement. Habituellement, cela est autorisé, et nous le faisons beaucoup. Quand, dans quelles circonstances peuvent-elles échouer?

Merci.

Était-ce utile?

La solution

Cela devrait fonctionner même avec plusieurs appartements à condition que:

  • Un seul des threads répond aux événements externes tels que le trafic réseau, les minuteries, les messages publiés, etc.
  • Autres threads uniquement des demandes de service Com (même s'ils rappellent le thread principal pendant le traitement).

ET

  • Aucune file d'attente ne devient pleinement pleine, empêchant COM de communiquer avec le fil.

Premièrement:Il semble que certains objets ne soient pas dans le même appartement que d'autres objets. Êtes-vous sûr que tous les objets sont créés dans le STA?

Ce que vous décrivez est une impasse classique - deux fils indépendants, chacun attendant l'autre. C'est ce que je m'attendrais à se produire avec cette conception fonctionnant avec les côtés C # et COM sur différents fils.

Tu devrais être OK si tout Les objets sont sur le même fil, ainsi que la fenêtre cachée sur ce fil, donc je pense que vous devez vérifier cela. (Évidemment, cela inclut tous les autres objets créés par le côté com et transmis au côté C #.)

Vous pouvez essayer de déboguer en appuyant sur "Pause" dans le débogueur et en vérifiant quel code était dans chaque fil (si vous voyez rpcrt * .dll Cela signifie que vous regardez un proxy). Alternativement, vous pouvez déboguer l'identifiant de thread actuel de divers points critiques dans les côtés C # et COM et votre wndproc - ils devraient tous être les mêmes.

Deuxièmement: Il devrait fonctionner avec plusieurs threads à condition qu'un seul des threads génère des éléments de travail, et l'autre ne fait que des objets com hôte qui répondent aux appels (c.-à-d. Ce cas peut être que la file d'attente de threads est pleine et que Com ne peut pas répondre à un appel.

Au lieu d'utiliser la file d'attente de thread, vous devez utiliser un désactive protégé par une section critique.

Vous pouvez maintenir un compteur d'articles sur / désactiver la file d'attente pour voir si c'est le problème.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top