문제

문제(더 명확하게 하기 위해 단순화됨):

    1.증가하는 함수가 있는 정적으로 연결된 static.lib가 하나 있습니다.
    
        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();
        }
    
    삼.테스트 앱에는 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 
        }
    

질문:

Don Box의 Essential .NET Vol1 The CLR에서 읽은 내용에 따르면 CreateInstanceAndUnwrap이 호출될 때 Managed.dll/static.lib의 새로운 복사본이 로드되므로 val2가 0이 될 것으로 예상합니다.무슨 일이 일어나고 있는지 오해하고 있습니까?정적 라이브러리는 관리되지 않는 코드이기 때문에 appdomain 경계를 존중하지 않는 것 같습니다.관리형 인스턴스화를 위한 새로운 프로세스를 만드는 것 외에 이 문제를 해결할 수 있는 방법이 있습니까?

정말 감사합니다!

도움이 되었습니까?

해결책

내 직감은 예상한 대로 관리되지 않는 DLL이 AppDomain의 컨텍스트가 아닌 프로세스의 컨텍스트에서 로드되므로 관리되지 않는 코드의 모든 정적 데이터가 AppDomain 간에 공유된다는 것입니다.

이 링크 귀하와 동일한 문제가 있는 사람이 있음을 보여 주지만 아직 100% 검증은 아니지만 아마도 그럴 것입니다.

이 링크 썽킹 트릭을 사용하여 관리되지 않는 코드에서 AppDomain으로 콜백을 만드는 방법에 관한 것입니다.이것이 도움이 될지는 모르겠지만 아마도 일종의 해결 방법을 만드는 데 유용할 것입니다.

다른 팁

전화하신 후

Managed c1 = new Managed(); 

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


}
`

중요사항:한 줄만 추가하면 JIT 컴파일러가 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 one

               AppDomain.Unload(ad)
    }
Managed c1 = new Managed(); 


}

이러한 라인에 의존하고 싶지 않다면 Managed.dll을 참조하고 호출 직후 도메인 언로드를 사용하여 별도의 도메인에서 각 호출을 수행하는 또 다른 래퍼 ManagedIsolated.dll을 만들 수 있습니다.기본 애플리케이션은 ManagedIsolated.dll 유형에만 의존하며 Managed.dll은 기본 앱 도메인에 로드되지 않습니다.

그것은 트릭처럼 보이지만 누군가에게는 유용할 수도 있습니다.`

요컨대 어쩌면.AppDomain은 순전히 관리되는 개념입니다.AppDomain이 인스턴스화되면 기본 DLL의 새 복사본에 매핑되지 않고 이미 메모리에 있는 코드를 재사용할 수 있습니다. 예를 들어 모든 System.* 어셈블리의 새 복사본을 로드할 것이라고는 예상할 수 없습니다. ?)

관리되는 세계 내에서 모든 정적 변수는 AppDomain에 의해 범위가 지정되지만, 지적한 대로 이는 관리되지 않는 세계에는 적용되지 않습니다.

각 앱 도메인에 대해 고유한 Managed.dll을 강제로 로드하는 복잡한 작업을 수행할 수 있으며, 이로 인해 새 버전의 정적 라이브러리가 함께 제공됩니다.예를 들어, 바이트 배열과 함께 Assembly.Load를 사용하면 작동할 수 있지만 동일한 어셈블리가 두 번 로드되는 경우 CLR이 유형의 충돌을 처리하려고 시도하는 방법을 모르겠습니다.

여기서는 실제 문제를 다루고 있지 않은 것 같습니다. 이 DDJ 기사를 참조하세요.

로더 최적화 속성의 기본값은 "AppDomain이 필요한 각 어셈블리 코드의 개인 복사본을 로드하게 하는" SingleDomain입니다.다중 도메인 값 중 하나이더라도 "모든 AppDomain은 항상 정적 필드의 고유한 복사본을 유지합니다".

'managed.dll'은 이름에서 알 수 있듯이 관리되는 어셈블리입니다.static.lib의 코드는 (IL 코드로) 'managed.dll'로 정적으로 컴파일되었으므로 Lenik이 기대하는 것과 동일한 동작을 기대할 수 있습니다....

...static.lib가 관리되지 않는 DLL에 대한 정적 내보내기 라이브러리가 아닌 경우.Lenik은 이것이 사실이 아니라고 말하므로 여기서 무슨 일이 일어나고 있는지 여전히 확신할 수 없습니다.

별도의 프로세스에서 실행해 보셨나요?정적 라이브러리는 자체 프로세스 외부에서 메모리 인스턴스를 공유해서는 안 됩니다.

관리하기가 어려울 수 있다는 것을 알고 있습니다.하지만 이 경우 다른 옵션이 무엇인지 잘 모르겠습니다.

편집하다:조금 둘러본 후에는 당신이 필요한 모든 것을 이 도구로 할 수 있을 것이라고 생각합니다. 시스템.진단.프로세스 수업.이 시점에서는 의사소통을 위한 많은 옵션이 있지만 .NET 원격 또는 WCF가 아마도 좋고 쉬운 선택일 것입니다.

이 주제에 관해 내가 찾은 최고의 기사 두 개는 다음과 같습니다.

중요한 부분은 다음과 같습니다.

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 배열도 작동할 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top