Domanda

Problema (semplificato per rendere le cose più chiare):

    1.c'è un link statico, statico.lib che ha una funzione che incrementa:
    
        extern int CallCount = 0;
        int TheFunction()
        {
            void *p = &CallCount;
            printf("Function called");
            return CallCount++;
        }
    
    2.statico.lib è collegato a un managed C++/CLI managed.dll che avvolge TheFunction metodo:
    
        int Managed::CallLibFunc()
        {
            return TheFunction();
        }
    
    3.Applicazione di Test ha un riferimento a managed.dll e consente di creare più domini che chiamano C++/CLI wrapper:
    
        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 
        }
    

Domanda:

Basato su quello che ho letto in Essenziale .NET Vol1 Il CLR di Don Box, mi sarei aspettato val2 essere pari a zero, poiché una marca nuova copia del gestito.dll/static.lib è caricato quando CreateInstanceAndUnwrap è chiamato.Sto equivoco che cosa sta accadendo?La libreria statica non sembra rispettare il dominio di applicazione confini, perché è il codice non gestito.C'è un modo per aggirare questo problema diverso da creazione di un nuovo processo per la creazione dell'istanza Gestito?

Grazie a tutti molto!

È stato utile?

Soluzione

La mia impressione è che, come si sospetta, non gestito Dll vengono caricate nel contesto del processo e non nel contesto del dominio di applicazione, quindi, dati statici nel codice non gestito è condivisa tra Appdomain.

Questo link mostra qualcuno con lo stesso problema, ancora non al 100%, la verifica di questo, ma probabilmente questo è il caso.

Questo link è sulla creazione di una richiamata dal codice non gestito in un AppDomain utilizzando un thunk trucco.Non so se questo può aiutare, ma forse troverete questo utile per creare un qualche tipo di soluzione.

Altri suggerimenti

Dopo la chiamata

Managed c1 = new Managed(); 

Il managed.dll wrapper sarà caricato in app principale dominio di applicazione.Fino a che ci sarà di dominio non gestito roba statica.lib sarà condivisa con altri domini.Invece di creare processo separato è solo bisogno di essere sicuri (prima di ogni chiamata) che managed.dll non è caricata in qualsiasi dominio di applicazione.

In termini di confronto con

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


}
`

IMPORTANTE e :Se si aggiunge un compilatore JIT sarà carico managed.dll e la magia scompare.

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(); 


}

Se non si vuole dipendere su tali linee si può creare un altro wrapper ManagedIsolated.dll che sarà di riferimento managed.dll e farà ogni chiamata di dominio separato con dominio scaricare solo dopo la chiamata.Applicazione principale dipenderà solo da ManagedIsolated.dll tipi e Managed.dll non sarà caricato in app principale di dominio.

Che sembra un trucco, ma può essere che sarà utile per qualcuno.`

In breve, forse.Appdomain sono puramente gestito concetto.Quando un dominio di applicazione viene creata un'istanza non mappa in nuove copie del sottostante Dll, è possibile riutilizzare il codice già in memoria (ad esempio, non ci si aspetterebbe per caricare le copie di tutto il Sistema.* assemblee, giusto?)

All'interno del mondo gestito tutte le variabili statiche ambito del dominio di applicazione, ma come dici tu questo non si applica nel mondo non gestito.

Si potrebbe fare qualcosa di più complesso che impone un carico di un unico managed.dll per ogni dominio dell'applicazione, il che comporterebbe una nuova versione del statica lib essere portato avanti per il giro.Per esempio, forse usando Assemblea.Caricare in un array di byte avrebbe funzionato, ma non so come CLR tentativo di affrontare la collisione in tipi di se stessa assemblea è caricato due volte.

Non penso che ci stiamo avvicinando al rilascio effettivo qui - vedere questo DDJ articolo.

Il valore predefinito per il caricatore di ottimizzazione attributo è SingleDomain, che "provoca il dominio di applicazione per caricare una copia privata di ogni necessario assemblea del codice".Anche se fosse uno dei Multi-dominio dei valori "ogni dominio di applicazione mantiene sempre una copia distinta di campi statici".

'managed.dll' è (come dice il nome stesso) è un assembly gestito.Il codice statico.lib è stato compilato staticamente (IL codice) in "managed.dll', quindi mi aspetto lo stesso comportamento Lenik si aspetta....

...a meno che non statico.lib è statico libreria di esportazione per una DLL non gestita.Lenik dice che questo non è il caso, quindi sono ancora sicuro di cosa sta succedendo qui.

Hai provato a correre in processi separati?Una libreria statica non dovrebbe condividere la memoria istanze al di fuori del proprio processo.

Questo può essere un dolore per la gestione, lo so.Io non sono sicuro di quello che il tuo altre opzioni sarebbe in questo caso però.

Edit:Dopo un po ' guardando in giro penso che si possa fare tutto il necessario per il Sistema.Diagnostica.Processo classe.Si avrebbe un sacco di opzioni, a questo punto, per la comunicazione, ma .NET Remoting o WCF sarebbe probabilmente essere bene e scelte facili.

Questi sono i due migliori articoli che ho trovato sull'argomento

La parte importante è:

RVA a base di campi statici sono processo globale.Queste sono limitate a scalari e i tipi di valore, perché non si desidera consentire oggetti a sanguinare attraverso AppDomain confini.Che potrebbe causare problemi di ogni genere, soprattutto durante il dominio di applicazione scaricata.Alcune lingue, come ILASM e MC++ rendere più conveniente per definire RVA a base di campi statici.La maggior parte delle lingue non.

Ok, quindi, se è possibile controllare il codice .lib, mi piacerebbe provare

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

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

Dal momento che ha detto che RVA a base di campi statici sono limitati per gli scalari e i tipi di valore.Una matrice di int potrebbe anche funzionare.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top