質問
問題 (わかりやすくするために単純化しています):
- 1.インクリメントする関数を持つ、静的にリンクされた static.lib が 1 つあります。
extern int CallCount = 0;
int TheFunction()
{
void *p = &CallCount;
printf("Function called");
return CallCount++;
}
2.static.lib は、TheFunction メソッドをラップするマネージド C++/CLI マネージド.dll にリンクされます。
int Managed::CallLibFunc()
{
return TheFunction();
}
3.テスト アプリにはマネージド.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
}
質問:
Don Box の『Essential .NET Vol1 The CLR』で読んだ内容に基づくと、CreateInstanceAndUnwrap が呼び出されたときに、managed.dll/static.lib の新しいコピーが読み込まれるため、val2 はゼロになると予想されます。何が起こっているのかを誤解していますか?静的ライブラリはアンマネージ コードであるため、アプリドメインの境界を尊重していないようです。マネージドをインスタンス化するためのまったく新しいプロセスを作成する以外に、この問題を回避する方法はありますか?
みなさん、本当にありがとうございました!
解決
他のヒント
電話した後
Managed c1 = new Managed();
マネージド.dll ラッパーは、アプリケーションのメイン アプリ ドメインにロードされます。それが実現するまで、static.lib のドメイン管理対象外のものは他のドメインと共有されます。別のプロセスを作成する代わりに、managed.dll がどのアプリケーション ドメインにも読み込まれていないことを (各呼び出しの前に) 確認するだけで済みます。
それと比較してください
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)
}
}
`
重要と:たった 1 行を追加すると、JIT コンパイラが Manageed.dll をロードし、魔法は消えます。
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();
}
このような行に依存したくない場合は、managed.dll を参照し、呼び出し直後にドメイン アンロードを使用して各呼び出しを別のドメインで行う別のラッパー ManagedIsolated.dll を作成できます。メイン アプリケーションは ManagedIsolated.dll タイプのみに依存し、Manized.dll はメイン アプリ ドメインにロードされません。
それはトリックのように見えますが、誰かにとって役立つかもしれません。`
要するに、たぶん。AppDomain は純粋に管理された概念です。AppDomain がインスタンス化されるとき、基になる DLL の新しいコピーにはマップされませんが、メモリ内にすでにあるコードを再利用できます (たとえば、すべての System.* アセンブリの新しいコピーを読み込むことは期待できませんよね。 ?)
マネージド環境内では、すべての静的変数のスコープは AppDomain によって決まりますが、指摘したように、これはアンマネージド環境では当てはまりません。
アプリ ドメインごとに一意のマネージド.dll の読み込みを強制するような複雑な操作を行うと、新しいバージョンの静的ライブラリが導入されることになります。たとえば、バイト配列で Assembly.Load を使用すると機能する可能性がありますが、同じアセンブリが 2 回読み込まれた場合に CLR が型の衝突をどのように処理しようとするかわかりません。
ここでは実際の問題には到達していないと思います - この DDJ の記事を参照してください.
ローダー最適化属性のデフォルト値は SingleDomain です。これにより、「AppDomain は、必要な各アセンブリのコードのプライベート コピーを読み込むことになります」。それがマルチドメイン値の 1 つである場合でも、「すべての AppDomain は常に静的フィールドの個別のコピーを維持します」。
「managed.dll」は (その名前が示すように) マネージド アセンブリです。static.lib のコードは (IL コードとして) 'managed.dll' に静的にコンパイルされているため、Lenik が期待しているのと同じ動作が期待できます。
...ただし、static.lib がアンマネージ DLL の静的エクスポート ライブラリである場合は除きます。レニック氏はそうではないと言っているので、ここで何が起こっているのかはまだわかりません。
別のプロセスで実行してみましたか?静的ライブラリは、それ自体のプロセスの外部でメモリ インスタンスを共有すべきではありません。
これを管理するのは難しいかもしれません。ただし、この場合、他の選択肢が何になるかはわかりません。
編集:少し見てみたところ、必要なことはすべてこれで実行できると思います。 システム.診断.プロセス クラス。この時点ではコミュニケーションの選択肢はたくさんあるでしょうが、 .NETリモーティング または WCF がおそらく適切で簡単な選択でしょう。
これらは、このテーマに関して私が見つけたベスト 2 つの記事です
- http://blogs.msdn.com/cbrumme/archive/2003/04/15/51317.aspx
- http://blogs.msdn.com/cbrumme/archive/2003/06/01/51466.aspx
重要な部分は次のとおりです。
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 配列も機能する可能性があります。