본문 바로가기

IT 살이/04. 기술 - 프로그래밍

05. ASP.NET 웹어플리케이션-쓰레드

ASP.NET 웹 어플리케이션에서 쓰레드 프로그래밍을 한다고 가정해보자.



이때 서버측 코드의 정적 필드는 어떤 단위로 격리될까? 예를 들어 static string s = “초기값”을 가지고 있는 쓰레드가 있다고 하자. 이 정적 필드 s를 같은 스레드에서 s=“다른값”으로 변경하면, 어디에서 “초기값”으로 조회되고, 어디에서 “다른값”으로 조회될까 고민해본 적 있다.


결론을 말하면 "같은 AppDomain과 같은 쓰레드"에서는 동일한 Thread Local Storage를 갖는다. 만약 ASP.NET 프로그램에서 명시적으로 AppDomain을 생성하지 않는다면 웹 어플리케이션과 AppDomain은 1:1이다. 하나의 AppDomain에서 쓰레드 프로그래밍을 하면 쓰레드별로 정적 필드가 관리된다는 것이다. 


Thread Local Storage: Thread-Relative Static Fields and Data Slots

https://msdn.microsoft.com/en-us/library/6sby1byh(v=vs.100).aspx

Whether you use thread-relative static fields or data slots, data in managed TLS is unique to the combination of thread and application domain.)



[업데이트 - 2016.01.28]


위 내용만으로는 웹 어플리케이션에서 static 변수를 편하게 사용할 수 있는 것처럼 보여져서 오해를 줄 수 있을 것 같다.


Application Class and Application Instances

https://support.microsoft.com/en-us/kb/312607


The ASP.NET runtime creates as many instances of application classes as needed to process requests simultaneously. For most applications, this number is limited to the number of threads and remains in the range of 1 through 100, depending on the hardware, server load, configuration, and so on. Many requests reuse application instances, and a free list of application instances is kept during periods of reduced load. Application instances are used in a thread-safe manner, that is, one request at a time. This has important implications: You do not have to worry about locking when you access non-static members of the application class. Application code can store request data for each request in non-static members of the application class (but not after the EndRequest event because this event may maintain the request for a long time). Because static members of any class, including an application class, are not thread-safe, the user code must provide appropriate locking for access to static members. This applies to any static member that you add to the application class.

"ASP.NET 런타임은 웹 어플리케이션의 인스턴스를 여러개 만들어서 풀에 두고 재사용을 한다.
어플리케이션 인스턴스는 thread-safe로 실행되어서 한번에 한 요청만 처리한다.
non-staic 멤버를 접근할때는 locking을 걱정할 필요없지만, 웹 어플리케이션 클래스에서 static 멤버를 사용하려면, locking을 해야 한다"


웹 어플리케이션이 실행되는 w3wp.exe 프로세스 자체는 하나만 실행되도록 설정할 수 있다(어플리케이션 풀 선택 > 고급설정...>프로세스 모델 영역 > 최대 작업자 프로세스 수 ). 

그러나 위 내용은 하나의 프로세스에서 여러개의 웹 어플리케이션이 실행된다는 것이다. 즉, ASP.NET은 동일한 어플리케이션을 하나의 프로세스내에서 여러개의 쓰레드로 실행시키고 있다는 것으로 해석할 수 있을 것 같다. 따라서 ASP.NET 프로그램에서 static 변수를 사용할때는 반드시 locking 처리를 해야한다는 것이다. 


static 멤버를 사용해야 한다면 sigleton 패턴을 고려해 볼 필요가 있다. 이 패턴을 사용하면 인스턴스를 얻는 부분에서만 locking 처리할 수 있다.


public class InternalCookieAppInfo

{

    static InternalCookieAppInfo u = null;

    static Object o = new Object();

    private internalCookieAppInfo() { }

    public static InternalCookieAppInfo Instance

    {

        get

        {

            lock (o)

            {

                if (u == null)

                {

                    u = new InternalCookieAppInfo();

                }

                return u;

            }

        }

    }

    public  string 속성01

    {

        get

        {...            }

        set

        {...            }

    }

...