Announcement

Collapse
No announcement yet.

Von verschiedenen Threads auf Com-Server zugreifen

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Von verschiedenen Threads auf Com-Server zugreifen

    Hallo,

    ich bin gerade dabei einen Corba-Server schreiben der Methoden bereit stellt, welche wiederrum dann auf einen Com-Serve zugreifen. Ich habe nur das Problem das die bereitgestellten Methoden vom Client mit unterschiedlichen Threads aufgerufen werden und ich dann nicht auf das selbe Com-Objekt zugreifen kann. Ich erhalte dann immer eine Exception.

    Also Beispiele wären diese Codefragemente...


    Datei.h

    #import "libid:E60738C2-DEE8-41E3-B538-9306544CB32F" //MyWrapper
    CComPtr<MyWrapper> pMyWrapper;


    Datei.cpp

    //Wird beim starten des Corba-Servers mit aufgerufen
    void init()
    {
    hr = CoInitialize(NULL);

    hr=pUnknown.CoCreateInstance(__uuidof(BEISPIELLib: :MyWrapper));

    hr=pUnknown->QueryInterface(&pMyWrapper);

    pMyWrapper->Methode1();
    }

    //Wird über Corba aufgerufen
    void deInit()
    {
    pMyWrapper->MEthode2();
    }

    Ich initialsiere beim starten des Com-Server die Mehtode init, welche dann als Thread läuft.
    Wenn ich dann über den Corba-Client die Methode2 aufrufe erhalte ich einen Exception bei pMyWrapper->Methode2(). Wie kann ich sicherstellen das ich von unterschiedlichen Threads auf das selbe Com-Objekt zugreife?
    Hat jemand eine Idee?

    Ich habe es bereits mit folgendes versucht...
    http://www.microsoft.com/germany/msd....mspx?mfr=true

    Am Ende der Methode1 gebe ich folgendes ein

    CoMarshalInterThreadInterfaceInStream (__uuidof(pMyWrapper), pMyWrapper, &pStream);

    und in der Methode2 rufe ich dann gleich beim start

    CoGetInterfaceAndReleaseStream (pStream, __uuidof(pMyWrapper), (void**) &pMyWrapper);
    Aber auch das bringt nicht.

    Gruß

    Rene
    Zuletzt editiert von ReneS; 12.12.2007, 17:20.

  • #2
    Hallo,
    soweit ich das erkennen kann, kämpfst du hier mit mehreren Problemem gleichzeitig.
    Punkt 1:
    Du hast nicht angegeben in welchen Apartment dein COM-Server läuft. Wenn nicht anders angegeben, dann wird das ein STA (Single Threaded Apartment) sein. D.h., dass kein multithreading unterstützt wird. Mann kann das auf andere Werte umstellen über den CoInitialize(...) Call bzw. CoInitializeEx(...) call im COM-Server.
    Punkt 2:
    Wenn du aus der Corbaseite multithreaded kommst und dann auf einen singlethreaded orientierten COM-Server triffst, mußt du den Zugriff darauf serialisieren. D.h. nur ein COM-Server Interfaceaufruf zur gleichen Zeit. D.h., dass dein Corba-Entrypunkt sowas wie einen Syncronisationspunkt benötigt.
    Punkt 3:
    Falls du den COM-Server im sog. "FreeThreaded" Modus betreibst, ist echtes multithreading möglich und damit auch gleichzeitiges aufrufen. D.h. aber, dass du auch für jeden Corbrathread einen eigenen Interfacepointer benötigst. Sharen dieser Interfacepointer ist nicht vorgesehen und kann übel ausgehen. Wenn der COM-Server das mitmacht, hast du allerdings eine höhere Last, wegen der andauernden Init/Use/Denit Sequenz, die beim benutzen des COM-Servers anfällt. Für diese Sachen gibt es dann den COM+ Dienst. Der hat dann das sog. pooling von COM-Servern und damit wird das eigentliche Freigeben, welches soviel Zeit frißt, unterbunden. Aber all das muß natürlich vor der Nutzung des COM-Servers geklärt werden.
    Punkt 4:
    Falls Freethreading dann wirklich eine Option ist, muß vom COM-Server aus natürlich auch eine entsprechende Verwaltung der nachgelagerten geshareten Resourcen erfolgen (DB, FileIO etc.).

    In der Regel ist jedoch der Aufwand für die Freethreading Implementierung zu hoch und man begnügt sich statt dessen mit einem selbstimplementierten pooling, welches dann für eine multithreading Nutzung des Interfaces herhalten muß. In so einem Szenario werden bei der Intitialisierung n Interfacepointer des COM-Servers in einer Liste (o.ae.) zwischengespeichert. Kommt nun ein Corba-Call im eigenen Thread daher, wird in der Liste (achtung Singleton notwendig) nach einen freien Eintrag gesucht und dieser als COM-Interfacepointer verwendet.
    Das ganze funktioniert so lange gut, bis es zu Fehlern kommt. Speziell Timouts sind hier ein Problem. Hier muß eine max. Laufzeit für die Aufrufe eingehalten werden, da die COM-Calls in der Regel bei den Timouts auf "INDEFINITE" stehen. Also warten bis zum Reset-Knopf...
    Als Vorteil ist eindeutig zu sagen, dass man hier alles unter Kontrolle hat und auch keine speziellen Anforderungen an den COM-Server stellen muß. Insofern also ein gangbarer Weg für die Nutzung von unbekannten COM-Servern.
    Ich empfehle dir in diesem Zusammenhang Lektüre zum Thema STA und anderen Threadmodellen im COM-Umfeld. Als mögliche Anlaufstellen zu diesem Thema kann man evtl. noch "http://www.codeproject.com" nennen. Dort gibt es jede Menge Artikel zu dieser Problematik.
    Viel Spaß noch.
    Gruß

    P.S.:
    Zu guter Letzt noch einen wichtigen Hinweis. Achte auf die Datentypen. Wenn das CORBA-Interface zu komplexe Datentypen als Parameter verwendet, kannst du dich zusätzlich noch mit den sog. "User defined Datatypes" unter COM rumschlagen. Und das ist nun wirklich ein sehr undankbares Thema...

    Comment


    • #3
      Hallo,

      ich versuche das gerade mit einem Cookie, aber wenn ich mir die Daten aus dem Cookie hole bleibt mein Programm stehen.
      Zur Info. Ich initialisere den Com-Server im Corba-Server jetzt so...

      Code:
       hr = CoInitialize(NULL); 
       
          //MyWrapper 
          hr=pUnknown.CoCreateInstance(__uuidof(MyWrapper));  
       
        //als CComPtr<IAsamWrapper> pMyWrapper; in der *.h deklariert 
          hr=pUnknown->QueryInterface(&pMyWrapper);  
           
           
          //in der selben Methode mache ich das hier; also selber Thread 
          cookie = 0; //Im Header deklariert: DWORD cookie; 
          git = 0; //Im Header deklariert: IGlobalInterfaceTable* git; 
       
          HRESULT hr = CoCreateInstance(CLSID_StdGlobalInterfaceTable, 0, CLSCTX_INPROC_SERVER, IID_IGlobalInterfaceTable, (void**) &git); 
           
          // OK, wir haben das Interface auf den GIT 
          hr = git->RegisterInterfaceInGlobal(pMyWrapper,__uuidof(MyWrapper), &cookie); 
          if (SUCCEEDED(hr)) 
          { 
              // OK, wir haben das interface im GIT registriert 
              assert(cookie != 0); 
          } 
          else 
              cookie = 0; 
       
          git->Release();
      die beiden anderen Com-Server werden in der selben Methode initialsiert. Kann ich da dann den selben Cookie nehmen? Oder wäre es besser wenn ich einfach cookie1, cookie2 und cookie3 anlegen würden?

      Im Com Corba-Client rufe ich eine andere Methode auf mit folgenden Inhalt:

      Code:
      CoInitialize(NULL); 
       
      git = 0; 
      HRESULT hr = CoCreateInstance(CLSID_StdGlobalInterfaceTable, 0, CLSCTX_INPROC_SERVER, IID_IGlobalInterfaceTable, (void**) &git); 
       
      if (SUCCEEDED(hr)) 
      { 
        CComPtr<IMyWrapper> pMyWrapper = 0; 
        // OK, wir haben das Interface auf den GIT 
        hr = git->GetInterfaceFromGlobal(cookie, __uuidof(MyWrapper), (void**) &pMyrapper); 
        if (SUCCEEDED(hr)) 
        { 
       
             hr = pMyWrapper->DeInit(); 
        } 
        git->Release(); 
      }
      und bei git->GetInterfaceFromGlobal bleibt mein Server und Client einfach stehen. Ohne Fehlermeldung.

      Woran liegt das? Was mache ich falsch?

      Comment

      Working...
      X