2008-09-16 5 views
4

Problem (vereinfacht die Dinge klarer zu machen):Statische Bibliotheken mit verwalteten Code Ausgabe

    1. es gibt eine statisch gelinkte static.lib, die eine Funktion hat, die erhöht:
    
        extern int CallCount = 0; 
        int TheFunction() 
        { 
         void *p = &CallCount; 
         printf("Function called"); 
         return CallCount++; 
        } 
    
    2. statisch. lib in einer verwalteten C++/CLI managed.dll verbunden, die TheFunction Verfahren wickelt:
    
        int Managed::CallLibFunc() 
        { 
         return TheFunction(); 
        } 
    
    3. Test app hat einen Referenz mehrere Domänen managed.dll und erzeugt die C++/CLI Wrapper nennen:
    
        static void Main(string[] args) 
        { 
         Managed c1 = new Managed(); 
         int val1 = c1.CallLibFunc(); 
         // value is zero 
    
         AppDomain ad = AppDomain.CreateDomain("NewDomain"); 
         Managed c = ad.CreateInstanceAndUnwrap(a.FullName, typeof(Managed).FullName) as Managed; 
         int val2 = c.CallLibFunc(); 
         // value is one 
        } 
    

Frage:

Nach dem, was ich in grundlegenden .NET Vol1 Die CLR von Don Box gelesen haben, würde ich erwarten, val2 Null, da eine brandneue Kopie von managed.dll sein/static.lib wird geladen wenn CreateInstanceAndUnwrap aufgerufen wird. Verkenne ich, was passiert? Die statische Bibliothek scheint die App-Domänengrenzen nicht zu respektieren, da es sich um nicht verwalteten Code handelt. Gibt es eine Möglichkeit, dieses Problem zu umgehen, indem Sie einen neuen Prozess für die Instanziierung von Managed erstellen?

Vielen Dank an alle!

+0

Wir haben das gleiche hier vor ein paar Jahren mit den gleichen Ergebnissen versucht. Wir erhalten immer nur eine Instanz des nicht verwalteten Codes. –

Antwort

3

Meine Vermutung war, dass nicht gemanagte DLLs im Kontext des Prozesses und nicht im Kontext der AppDomain geladen werden, so dass statische Daten in nicht verwaltetem Code unter AppDomains gemeinsam genutzt werden.

This link zeigt jemand mit dem gleichen Problem, das Sie haben, noch nicht 100% Verifizierung von diesem, aber wahrscheinlich ist dies der Fall.

This link ist das Erstellen eines Rückrufs von nicht verwaltetem Code in eine Anwendungsdomäne mit einem Thunk-Trick. Ich bin mir nicht sicher, ob dir das helfen kann, aber vielleicht findest du das nützlich, um eine Art Workaround zu erstellen.

0

Kurz gesagt, vielleicht. AppDomains sind ein reines Managed-Konzept. Wenn eine AppDomain instanziiert wird, werden keine neuen Kopien der zugrunde liegenden DLLs zugeordnet. Sie können den bereits im Speicher vorhandenen Code wiederverwenden (beispielsweise würden Sie nicht erwarten, dass neue Kopien aller System.-Assemblys geladen werden, richtig ?)

Innerhalb der verwalteten Welt sind alle statischen Variablen durch AppDomain definiert, aber wie Sie darauf hinweisen, gilt dies nicht in der nicht verwalteten Welt.

Sie könnten etwas Komplexes tun, das eine Last einer einzigartigen managed.dll für jede App-Domäne erzwingt, was dazu führen würde, dass eine neue Version der statischen lib für die Fahrt mitgenommen wird. Beispielsweise könnte die Verwendung von Assembly.Load mit einem Bytearray funktionieren, aber ich weiß nicht, wie die CLR versuchen wird, mit der Kollision in Typen umzugehen, wenn dieselbe Assembly zweimal geladen wird.

0

Ich denke nicht, dass wir hier zum eigentlichen Problem kommen - see this DDJ article.

Der Standardwert des Loader-Optimierungsattributs ist SingleDomain, wodurch "die AppDomain eine private Kopie des Codes jeder erforderlichen Assembly lädt". Selbst wenn es sich um einen der Multi-Domain-Werte handelt, "verwaltet jede AppDomain immer eine eigene Kopie statischer Felder".

'managed.dll' ist (wie der Name schon sagt) eine verwaltete Assembly. Der Code in static.lib wurde statisch (als IL-Code) in 'managed.dll' kompiliert, also würde ich das gleiche Verhalten erwarten, wie Lenik es erwartet.

...es sei denn, static.lib ist eine statische Exportbibliothek für eine nicht verwaltete DLL. Lenik sagt, das ist nicht der Fall, also bin ich mir immer noch nicht sicher, was hier vor sich geht.

+0

Die MSDN-Dokumentation für LoaderOptimizationAttribute besagt, dass "dieses Attribut nur ein Hinweis auf den Loader ist und das Programmverhalten nicht beeinflusst." Also was auch immer es tut, es sollte das beobachtete Verhalten nicht ändern können, kann also hier keine Rolle spielen. –

0

Haben Sie versucht, in separaten Prozessen zu laufen? Eine statische Bibliothek sollte Speicherinstanzen nicht außerhalb ihres eigenen Prozesses freigeben.

Dies kann ein Schmerz sein, zu verwalten, ich weiß. Ich bin mir nicht sicher, was Ihre anderen Optionen in diesem Fall sein würden.

Edit: Nach ein wenig Umschauen denke ich, dass Sie alles mit der System.Diagnostics.Process Klasse tun könnten. Sie hätten an dieser Stelle viele Möglichkeiten zur Kommunikation, aber .NET Remoting oder WCF wären wahrscheinlich gute und einfache Entscheidungen.

0

Dies sind die besten zwei Artikel, die ich über das Thema

  • http://blogs.msdn.com/cbrumme/archive/2003/06/01/51466.aspx
  • Der wichtigste Teil ist

    • http://blogs.msdn.com/cbrumme/archive/2003/04/15/51317.aspx
    • gefunden:

      RVA-basierte statische Felder sind Prozess -global. Diese sind auf Skalare und Werttypen beschränkt, da Objekte nicht über AppDomain-Grenzen hinweg bluten dürfen. Das würde alle möglichen Probleme verursachen, besonders während des Entladens von AppDomain. Einige Sprachen wie ILASM und MC++ machen es einfach, RVA-basierte statische Felder zu definieren. Die meisten Sprachen nicht.

      Ok, also, wenn Sie den Code in der LIB-Steuerung, würde ich

      class CallCountHolder { 
          public: 
          CallCountHolder(int i) : count(i) {} 
          int count; 
      }; 
      
      static CallCountHolder cc(0); 
      int TheFunction() 
      { 
          printf("Function called"); 
          return cc.count++; 
      } 
      

      versuchen Da er sagte, dass RVA-basierte statische Felder auf Skalare und Werttypen beschränkt sind. Ein int-Array könnte auch funktionieren.

    1

    Nachdem Sie

    Managed c1 = new Managed(); 
    

    Ihr managed.dll Wrapper wird rufen geladen in den Hauptanwendungsdomäne von Ihnen Anwendung. Bis es da sein wird, wird Domain unmanaged stuff von static.lib mit anderen Domains geteilt. Anstatt separaten Prozess zu erstellen, müssen Sie nur sicher sein (vor jedem Aufruf), dass die Datei "managed.dll" nicht in eine Anwendungsdomäne geladen wird.

    Vergleich mit diesen

    static void Main(string[] args) 
    { 
    
        {  
           AppDomain ad = AppDomain.CreateDomain("NewDomain"); 
           Managed c = ad.CreateInstanceAndUnwrap(a.FullName, typeof(Managed).FullName) as Managed; 
           int val2 = c.CallLibFunc(); 
           // Value is zero 
    
           AppDomain.Unload(ad) 
        } 
        {  
           AppDomain ad = AppDomain.CreateDomain("NewDomain"); 
           Managed c = ad.CreateInstanceAndUnwrap(a.FullName, typeof(Managed).FullName) as Managed; 
           int val2 = c.CallLibFunc(); 
           // I think value is zero 
    
           AppDomain.Unload(ad) 
        } 
    
    
    } 
    ` 
    

    WICHTIG und: Wenn Sie nur eine Zeile JIT-Compiler hinzufügen laden managed.dll und die Magie verschwindet.

    static void Main(string[] args) 
    { 
    
        {  
           AppDomain ad = AppDomain.CreateDomain("NewDomain"); 
           Managed c = ad.CreateInstanceAndUnwrap(a.FullName, typeof(Managed).FullName) as Managed; 
           int val2 = c.CallLibFunc(); 
           // Value is zero 
    
           AppDomain.Unload(ad) 
        } 
        {  
           AppDomain ad = AppDomain.CreateDomain("NewDomain"); 
           Managed c = ad.CreateInstanceAndUnwrap(a.FullName, typeof(Managed).FullName) as Managed; 
           int val2 = c.CallLibFunc(); 
           // I think value is one 
    
           AppDomain.Unload(ad) 
        } 
    Managed c1 = new Managed(); 
    
    
    } 
    

    Wenn Sie nicht wollen, auf solchen Linien hängen Sie einen anderen Wrapper ManagedIsolated.dll erstellen können, die managed.dll Referenz und wird jeden Anruf in separater Domäne mit Domäne Entladen kurz nach dem Anruf. Die Hauptanwendung hängt nur von ManagedIsolated.dll-Typen ab, und Managed.dll wird nicht in die Haupt-App-Domäne geladen.

    Das sieht wie ein Trick aus, aber möglicherweise ist es für jemand nützlich. `

    Verwandte Themen