Frage

Problem (vereinfacht, um die Dinge klarer):

    1. Dort ist eine statisch gelinkte static.lib, die eine Funktion hat, die inkrementiert:
    
        extern int CallCount = 0;
        int TheFunction()
        {
            void *p = &CallCount;
            printf("Function called");
            return CallCount++;
        }
    
    2. static.lib wird in eine verwaltete C ++ / CLI managed.dll verbunden, die TheFunction Verfahren wickelt:
    
        int Managed::CallLibFunc()
        {
            return TheFunction();
        }
    
    3. Test Anwendung hat einen Verweis auf managed.dll und erzeugt mehrere Domänen, 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 grundlegendem .NET Vol1 Die CLR von Don Box gelesen habe, würde ich erwarten, val2 Null, da eine brandneue Kopie von managed.dll / static.lib sein wird geladen, wenn CreateInstanceAndUnwrap genannt wird. Bin ich Missverständnis, was geschieht? Die statische Bibliothek scheint nicht die Appdomain Grenzen respektiert werden, da es nicht verwalteten Code. Gibt es eine Möglichkeit, um dieses Problem andere zu bekommen, als durch ein brandneues Verfahren für die Erstellung von Managed Instanziieren?

Vielen Dank alle!

War es hilfreich?

Lösung

Meine Vermutung war, dass, wie Sie vermutet, nicht verwalteten DLLs im Rahmen des Prozesses geladen wird und nicht im Rahmen der AppDomain, so dass alle statischen Daten in nicht verwalteten Code wird unter AppDomains geteilt.

diesen Link zeigt jemand mit dem gleichen Problem, das Sie haben, immer noch nicht zu 100% Überprüfung diesen, aber wahrscheinlich ist dies der Fall.

Dieser Link ist über einen Rückruf der Erstellung von unmanaged Code in eine AppDomain einen Thunk Trick. Ich bin mir nicht sicher, dass diese Ihnen helfen können, aber vielleicht werden Sie diesen Kommentar hilfreich irgendeine Art von Problem zu umgehen erstellen.

Andere Tipps

Nachdem Sie rufen

Managed c1 = new Managed(); 

Ihr managed.dll Wrapper wird in der Hauptanwendungsdomäne von Ihnen Anwendung geladen werden. Bis es dort Domain nicht verwalteten Sachen aus static.lib ist, werden mit anderen Domänen geteilt werden. Anstelle von separaten Prozess Erstellen Sie müssen nur sicher sein (vor jedem Anruf), dass managed.dll nicht geladen wird in jede Anwendungsdomäne.

mit, dass der Vergleich

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 lädt 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 wollen nicht 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 machen nur nach dem Aufruf. Hauptanwendung wird nur auf ManagedIsolated.dll Typen und Managed.dll abhängig ist, nicht in der Hauptanwendungsdomäne geladen werden.

Das sieht aus wie ein Trick, aber kann es für jemanden nützlich sein.     `

Kurz gesagt, vielleicht. AppDomains sind rein ein verwaltetes Konzept. Wenn ein AppDomain instanziiert wird es nicht in neuen Kopien des zugrunde liegenden DLLs abbildet, kann er den Code bereits im Speicher (zB die Wiederverwendung, würden Sie nicht erwarten, dass es neue Kopien alle Systems zu laden. * Baugruppen, rechts ?)

In der verwalteten Welt alle statischen Variablen von AppDomain scoped sind, aber wie Sie dies darauf hin, nicht in der nicht verwalteten Welt nicht gelten.

Sie könnten etwas komplexer tun, die für jede Anwendungsdomäne eine Last von einem einzigartigen managed.dll Kräften, die für die Fahrt gebracht in einer neuen Version der statischen lib Wesen führen würden. Zum Beispiel würde vielleicht mit Assembly.Load mit einem Byte-Array arbeiten, aber ich weiß nicht, wie die CLR versucht, mit der Kollision in Arten zu behandeln, wenn die gleiche Baugruppe zweimal geladen wird.

Ich glaube nicht, dass wir hier an der aktuellen Ausgabe sind immer - diesen DDJ-Artikel .

Der Standardwert des Laders Optimierung Attribut ist SingleDomain, die „die AppDomain verursacht eine private Kopie jeder erforderlichen Assembly Code zu laden“. Selbst wenn es eine der Multi-Domain-Werte „jeder AppDomain immer unterhält eine eigene Kopie der statischen Felder“.

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

... es sei denn, static.lib ist eine statische Export-Bibliothek für eine nicht verwaltete DLL. Lenik sagt dies nicht der Fall ist, so bin ich noch nicht sicher, was hier los ist.

Haben Sie versucht, in separaten Prozessen ausgeführt werden? Eine statische Bibliothek sollte nicht Speicher-Instanzen außerhalb von seinem eigenen Prozess teilen.

Dies kann ein Schmerz zu verwalten, ich weiß. Ich bin mir nicht sicher, was Ihre andere Optionen obwohl in diesem Fall wären.

Edit: Nach ein wenig umsah ich glaube, Sie alles tun, könnten Sie mit der System.Diagnostics.Process Klasse. Sie würden für die Kommunikation an dieser Stelle eine Menge von Optionen haben, aber .NET Remoting oder WCF wäre wahrscheinlich gut und einfach Wahl.

Dies sind die besten zwei Artikel, die ich zu dem Thema gefunden

Der wichtigste Teil ist:

  

RVA-basierte statische Felder sind prozess global. Diese beschränken sich auf Skalare und Werttypen, weil wir nicht wollen, Objekte zu ermöglichen, über AppDomain Grenzen zu bluten. Das würde alle möglichen Probleme verursachen, besonders bei AppDomain leert. Einige Sprachen wie ILASM und MC ++ machen es bequem RVA-basierte statische Felder zu definieren. Die meisten Sprachen nicht.

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

class CallCountHolder {
   public:
     CallCountHolder(int i) : count(i) {}
     int count;
};

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

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

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top