4

問題(わかりやすくするために簡略化):

    1.インクリメントする関数を持つ静的にリンクされた static.lib が 1 つあります。
    
        extern int CallCount = 0;
        int TheFunction()
        {
            void *p = &CallCount;
            printf("Function called");
            return CallCount++;
        }
    
    2. static.lib は、TheFunction メソッドをラップするマネージド C++/CLI managed.dll にリンクされます。
    
        int Managed::CallLibFunc()
        {
            return TheFunction();
        }
    
    3. テスト アプリには managed.dll への参照があり、C++/CLI ラッパーを呼び出す複数のドメインを作成します。
    
        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 
        }
    

質問:

Essential .NET Vol1 The CLR by Don Box で読んだ内容に基づいて、CreateInstanceAndUnwrap が呼び出されたときに managed.dll/static.lib の新しいコピーが読み込まれるため、val2 はゼロであると予想されます。何が起こっているのか誤解していますか?静的ライブラリは管理されていないコードであるため、appdomain の境界を尊重していないようです。Managed をインスタンス化するためのまったく新しいプロセスを作成する以外に、この問題を回避する方法はありますか?

皆様、本当にありがとうございました!

4

6 に答える 6

3

ご想像のとおり、アンマネージ DLL は AppDomain のコンテキストではなくプロセスのコンテキストで読み込まれるため、アンマネージ コードの静的データは AppDomain 間で共有されます。

このリンクは、あなたと同じ問題を抱えている人を示していますが、まだ 100% 検証されていませんが、おそらくこれが当てはまります。

このリンクは、サンク トリックを使用して、アンマネージ コードから AppDomain へのコールバックを作成することに関するものです。これが役立つかどうかはわかりませんが、何らかの回避策を作成するのに役立つかもしれません。

于 2008-09-16T14:41:35.253 に答える
0

これらは、この件に関して私が見つけた最高の2つの記事です

重要な部分は次のとおりです。

RVA ベースの静的フィールドはプロセス グローバルです。オブジェクトが AppDomain の境界を越えて出血することを許可したくないため、これらはスカラーと値の型に制限されています。これは、特に AppDomain のアンロード中に、あらゆる種類の問題を引き起こす可能性があります。ILASM や MC++ などの一部の言語では、RVA ベースの静的フィールドを簡単に定義できます。ほとんどの言語はそうではありません。

わかりました.libのコードを制御する場合は、試してみます

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

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

彼は、RVA ベースの静的フィールドはスカラーと値の型に限定されていると述べました。int 配列も機能する場合があります。

于 2008-10-01T14:02:18.137 に答える
0

ここで実際の問題に到達しているとは思いません。この DDJ の記事を参照してください

ローダー最適化属性のデフォルト値は SingleDomain で、「AppDomain が必要な各アセンブリ コードのプライベート コピーをロードするようにします」。それがマルチ ドメイン値の 1 つであったとしても、「すべての AppDomain は常に静的フィールドの個別のコピーを維持します」。

「managed.dll」は (その名前が示すように) マネージ アセンブリです。static.lib のコードは、(IL コードとして) 'managed.dll' に静的にコンパイルされているため、Lenik が期待するのと同じ動作が期待できます....

... static.lib がアンマネージ DLL の静的エクスポート ライブラリでない限り。レニクはそうではないと言っているので、ここで何が起こっているのかまだわかりません.

于 2008-09-16T15:00:02.480 に答える
0

Have you tried running in separate processes? A static library should not share memory instances outside of it's own process.

This can be a pain to manage, I know. I'm not sure what your other options would be in this case though.

Edit: After a little looking around I think you could do everything you needed to with the System.Diagnostics.Process class. You would have a lot of options at this point for communication but .NET Remoting or WCF would probably be good and easy choices.

于 2008-09-18T14:38:32.420 に答える
0

要するに、多分。AppDomains は純粋に管理された概念です。AppDomain がインスタンス化されると、基になる DLL の新しいコピーにマップされず、既にメモリ内にあるコードを再利用できます (たとえば、すべての System.* アセンブリの新しいコピーを読み込むとは思わないでしょう。 ?)

管理された世界では、すべての静的変数は AppDomain によってスコープされますが、ご指摘のとおり、これは管理されていない世界には当てはまりません。

アプリ ドメインごとに一意の managed.dll を強制的にロードする複雑な処理を行うことができます。これにより、新しいバージョンの静的ライブラリが一緒に運ばれます。たとえば、バイト配列で Assembly.Load を使用するとうまくいくかもしれませんが、同じアセンブリが 2 回読み込まれた場合に、CLR が型の衝突をどのように処理しようとするのかわかりません。

于 2008-09-16T14:47:28.093 に答える