잊지 않겠습니다.

'AppDomain'에 해당되는 글 3건

  1. 2009.03.01 AppDomain을 이용한 개발(3)
  2. 2009.03.01 AppDomain을 이용한 개발(2)
  3. 2009.02.26 AppDomain을 이용한 개발(1)
마지막으로 Thread에 safe 하지 못한 약점을 극복하기 위한 방법은 은근히 간단하다.
.NET 에서 Process -> AppDomain -> Thread -> Context 단위로 동작하기 때문에, Thread에 safe 한 상황은 Process에서 역시 safe 한 상황이 되어야지 된다.

이는 여러개의 Process에서 같은 자원을 사용하는 상황과 거의 동일하기 때문에, Thread에서 사용되는 ManualResetEvent, AutoResetEvent, lock, Monitor 등을 사용하게 되면, 절대로 Thread safe가 될 수가 없다.

따라서, Process단위의 자원 격리가 필요하다. 이를 위해서, Mutex나 Semaphore를 사용하면 간단히 구현 가능하다. ^^
Posted by Y2K
,
먼저, AppDomain을 이용한 개발을 하는 가장 큰 장점은 Process보다 더 가벼운 단위로의 동작이 가능하고, Programming 적으로 동작이 가능하다는 장점을 가지고 있다. 그렇지만, 이러한 동작 및 Resource의 제어를 하기 위해서 모든 AppDomain를 제어하고, Process당 하나만 존재하는 진정한 Singleton object가 필요하게 된다.

이 Singleton object를 만들기 위한 컨셉은 다음과 같다.

Singleton object가 동작할 working AppDomain의 지정


using System;
using System.Runtime.InteropServices;

namespace ProxyServerForMsn.AppDomainManager
{
    public class CrossAppDomainSingleton<T> : MarshalByRefObject where T : new()
    {
        private const string AppDomainName = "Singleton AppDomain";
        // Singleton Working AppDomain 지정
        private static T instance;

        public static void ListupAppDomains()
        {
            IntPtr enumHandle = IntPtr.Zero;
            mscoree.CorRuntimeHostClass host = new mscoree.CorRuntimeHostClass();
            try
            {
                host.EnumDomains(out enumHandle);

                object domain = null;
                while(true)
                {
                    host.NextDomain(enumHandle, out domain);
                    if(domain == null)
                    {
                        break;
                    }
                    AppDomain appDomain = domain as AppDomain;
                    if(appDomain != null)
                    {
                        Console.WriteLine(appDomain.FriendlyName);   
                    }
                }
            }
            finally
            {
                host.CloseEnum(enumHandle);
                Marshal.ReleaseComObject(host);
                host = null;
            }
        }

        private static AppDomain GetAppDomain(string friendlyName)
        {
            IntPtr enumHandle = IntPtr.Zero;
            mscoree.CorRuntimeHostClass host = new mscoree.CorRuntimeHostClass();
            try
            {
                host.EnumDomains(out enumHandle);

                object domain = null;
                while(true)
                {
                    host.NextDomain(enumHandle, out domain);
                    if(domain == null)
                    {
                        break;
                    }
                    AppDomain appDomain = (AppDomain)domain;
                    if(appDomain.FriendlyName.Equals(friendlyName))
                    {
                        return appDomain;
                    }
                }
            }
            finally
            {
                host.CloseEnum(enumHandle);
                Marshal.ReleaseComObject(host);
                host = null;
            }
            return null;
        }

        public static T Instance
        {
            get
            {
                if (null == instance)
                {
                    AppDomain appDomain = GetAppDomain(AppDomainName);
                    if (null == appDomain)
                    {
                        appDomain = AppDomain.CreateDomain(AppDomainName);
                    }
                    Type type = typeof (T);
                    T createInstance = (T) appDomain.GetData(type.FullName);
                    if (null == createInstance)
                    {
                        createInstance =
                            (T) appDomain.CreateInstanceAndUnwrap(type.Assembly.FullName, type.FullName);
                        appDomain.SetData(type.FullName, createInstance);
                    }
                    instance = createInstance;
                }
                return instance;
            }
        }
    }
}


Generic으로 만들어져있기 때문에, 사용될 constraint class의 경우에도 MarsharByObject class를 상속받거나 Serializable 속성을 가져야지 된다.

사용은 다음과 같다.

[Serializable]
public class CrossAppHello
{
public void ConsoleOut()
{
Console.WriteLine("Hello World");
}
}

class Program
{
public static void Main()
{
CrossAppDomainSingleton<CrossAppHello>.Instance.ConsoleOut();
}
}

Posted by Y2K
,
.NET에서의 Application의 구조는 Process->Application Domain->Thread->Context 로 구성이 된다.

일반적으로 개발되는 console app들은 한개의 Process를 가지고, 이는 실행 파일의 이름과 동일한 Default AppDomain을 가지게 된다. 거의 대부분의 프로그램들이 1개의 AppDomain으로 동작하게 되어서, 일반적으로 사용할때는 Process = AppDomain의 형태로 프로그램의 제작이 가능하다.

그렇지만, 1개의 Process에서 여러개의 AppDomain을 가지게 되는 프로그램들이 꼭 필요하게 되는데. 대표적인 프로그램이 IIS라고 할 수 있다. IIS의 동작은 iis_work에 대한 한개의 Process에서 각 Http Application의 접속 Connection에 따라서, 각각 AppDomain을 작성하게 되는데. Application Domain으로 동작하게 되면, 다음과 같은 장점이 있다.

1. Process 단위로 동작하는 것으로 가정하고 프로그래밍이 가능하다.
2. Process로 동작되는 것보다 시스템 리소스 소모가 작다.
3. 관리된 이름으로의 접근이 가능하다.

string appDomainName = string.Format("Server[{0:HH:mm:ss}_{1}]", DateTime.Now, DateTime.Now.Millisecond);
AppDomain appDomain = AppDomain.CreateDomain(appDomainName);
- AppDomain 생성

Console.WriteLine("Start AppDomain : {0}", appDomainName);
ProxySocketHandler proxySocketHandler = (ProxySocketHandler)appDomain.CreateInstanceAndUnwrap(
                                                                 Assembly.GetExecutingAssembly().FullName,
                                                                 "ProxyServerForMsn.SocketHandler.ProxySocketHandler");
- 생성된 AppDomain에서 Instace 생성

AppDomain 단위로 개발을 하게 되면 가장 큰 장점이라고 할 수 있는 것이.. 결국은 리소스의 관리에서 좀 더 원활한 개발을 할 수 있게 된다는 점이다. 그렇지만, AppDomain단위로 개발하는 것이 언제나 좋은 것은 아니다. 개발에서 귀찮은 점이 두가지가 생기게 된다. 하나는 static instance에 대한 사항이고, 나머지 하나는 thread safe에 대한 고려사항이다.

먼저, static instance는 모든 Process당 한개의 고정된 Instance를 보장하지 않는다. 정확히 .NET에서 static intance는 Process 당이 아닌 모든 AppDomain에 해당되는 single instance를 의미한다. 우리가 일반적으로 사용하는 application에서 이와 같은 점이 고려되지 않는 이유는 거의 대부분의 application들이 하나의 AppDomain만을 가지고 있기 때문이다. 이 점이 IIS에서 아무리 class들을 static으로 만들어도, 모든 web page나 connection에서 static instance 또는 method로 사용할 수 없는 이유가 된다.

그리고, thread safe에 대한 고려사항이다. 결론적으로 이야기 한다면, 일반적으로 thread safe를 보장하기 위해서 사용되는 lock 키워드나, ManualResetEvent, AutoResetEvent를 모두 사용하지 못한다. 이러한 방법들은 모두 한개의 AppDomain에서 동작하는 Thread들에서 서로간의 간섭을 알 수 있지, 다른 AppDomain에서의 간섭을 전혀 알지 못한다. Thread에 대한 friendly name은 내부적으로 AppDomainName과 ThreadName의 조합으로 만들어지기 때문에 이와 같은 사항을 전혀 고려할 수 없게 된다.


Posted by Y2K
,