분류 전체보기 (328)
.NET (111)
S/W tip (35)
etc (63)
DB (34)
HOT item~! (48)
Disign pettens (4)
UX (6)
나의 S/W (2)
개발관련 이슈 (16)
Diary (1)
웹플러스 (1)
calendar
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
tags
archive
link
ColorSwitch 00 01 02
▣  XML & XSD Paser - 2009. 5. 14. 17:55

보호되어 있는 글입니다. 내용을 보실려면 비밀번호를 입력하세요.


▣  C# Thread-safety(쓰레드 안전성) - .NET/C# - 2009. 5. 14. 14:38

http://blog.naver.com/dolmoon/60050722794

쓰레드 안전성(thread-safety)


쓰레드 안전성(Thread safety)의 정의 - Thread safety is a computer programming concept applicable in the context of multi-threaded programs. A piece of code is thread-safe if it functions correctly during simultaneous execution by multiple threads. In particular, it must satisfy the need for multiple threads to access the same shared data, and the need for a shared piece of data to be accessed by only one thread at any given time.(출처 : wikipdia)
요약하자면, 쓰레드 안전성(Thread-Safety)은 둘 이상의 쓰레드가 서로 공유하는 데이터를 사용할 때는 주어진 시간에 오직 하나의 쓰레드만 접근 가능하게 하여 각각의 쓰레드가 오동작하지 않도록 하는 것이다. 즉, 하나의 쓰레드가 데이터에 접근하여 이미 사용하고 있다면, 다른 쓰레드는 해당 데이터에 접근하지 못하도록 하는 것이다.


using System;
using System.Threading;

namespace ThreadTest
{

    //다음은 안전하지 않은 쓰레드(Unsafe thread)의 예이다.
    class UnsafeThreadSample
    {
        private static string _sharedData;
        private static int _currentThreadNo;

        public UnsafeThreadSample(string testData)
        {
            _sharedData = testData;
        }

        public static void WriteSharedDataUnsafely()
        {
            Console.WriteLine(_sharedData + _currentThreadNo + "\t");
            Thread.Sleep(1000);
            _currentThreadNo += 1;
        }
    }

 

    class SafeThreadSample
    {
        private static string _sharedData;
        private static int _currentThreadNo;

        //Thread의 안전성을 확보하기 위해 object 개체를 하나 생성
        private static object dummy = new object();

        public SafeThreadSample(string testData)
        {
            _sharedData = testData;
        }

        public static void WriteSharedDataSafely()
        {

            //lock으로 공유데이터인 _sharedData, _currentThreadNo를 사용하는 동안

            //다른 프로세스는 대기하도록 설정함.
            lock(dummy)
            {
                Console.WriteLine(_sharedData + _currentThreadNo + "\t");
                Thread.Sleep(1000);
                _currentThreadNo += 1;
            }
        }
    }

 

    static class TestRun
    {
        public static void Main()
        {
            int safeThreadCount = 0;

            int unSafeThreadCount = 0;
            SafeThreadSample safeInstance = new SafeThreadSample("Safe");

            UnsafeThreadSample unsafeInstance = new UnsafeThreadSample("Unsafe");

            //안전한 쓰레드 반복 실행(각 쓰레드가

            while (safeThreadCount < 10)
            {

                //Thread개체 생성
                Thread safeThread = new Thread(new ThreadStart(SafeThreadSample.WriteSharedDataSafely));
                //Thread 시작

                safeThread.Start();
                safeThreadCount++;
            }


            //안전하지 않은 쓰레드 반복실행

            while(unSafeThreadCount < 10)
            {

                //Thread개체 생성
                Thread unsafeThread = new Thread(new ThreadStart(UnsafeThreadSample.WriteSharedDataUnsafely));

                //Thread 시작

                unsafeThread.Start();
                unSafeThreadCount++;
            }

            Console.ReadLine();
        }
    }
}

//출력 결과는 다음과 같다. 프로그램을 실행하는 환경에 따라서 결과는 달라질 수 있다.
Safe0     Unsafe0 Unsafe0 Unsafe0 Unsafe0 Unsafe0 Unsafe0 Unsafe0 Unsafe0 Unsafe0
Unsafe0 Safe1    Safe2     Safe3    Safe4     Safe5   Safe6   Safe7   Safe8   Safe9


출력 결과를 보면, 첫 번째 안전한 쓰레드(safeThread)가 실행되어 WriteSharedDataSafely()메서드에서 1초 간 기다리는 동안 unsafeThread가 모두 실행되어버렸다는 것을 알 수 있다. 또한, safeThread는 순차적으로 0에서 9까지 실행된 반면(실제로는 여러 쓰레드가 실행될 때 쓰레드의 실행순서는 보장되지 않지만, 여기서는 쓰레드가 순차적으로 실행되었다고 간주한다. 순차적으로 실행되지 않았더라도 출력 결과는 같을 것이다), unsafeThread는 첫 번째unsafeThread가 WriteSharedDataUnsafely() 메서드를 완료하기 전에, 좀 더 정확하게는 _currentThreadNo += 1; 문장이 실행하기 전에 Console.WriteLine(_sharedData + _currentThreadNo + "\t"); 문장을 모두 실행해 버렸다는 것도 알 수 있다.  다시 말해, unsafeThread의 경우 이전 쓰레드가 _currentThreadNo의 값을 증가시키기 전에 _currentThreadNo값을 사용함으로써 원래 의도와는 다른 결과를 만들어 냈다는 것이다.


참고로 위의 예제에서 UnsafeThreadSample 클래스에 있는 Thread.Sleep(1000); 문장을 지우고 다시 실행하면 그 결과는 다음과 같다.

 

Safe0   Unsafe0 Unsafe1 Unsafe2 Unsafe3 Unsafe4 Unsafe5 Unsafe6 Unsafe7 Unsafe7
Unsafe9 Safe1   Safe2   Safe3   Safe4   Safe5   Safe6   Safe7   Safe8   Safe9

 

새로운 결과는 이전 결과와 다르긴 하지만 Unsafe7이 두 번 반복되는 것을 볼 수 있어 쓰레드 안전성이 확보되지 않았다는 것을 알 수 있다.

위의 결과에서 또 한가지 눈여겨 볼 것은 lock을 써서 쓰레드 안전성을 확보하는 것은 lock을 쓰지 않은 경우와 비교해 상대적으로 속도면에서 손실이 있을 것이라는 점이다. 결국 위의 예제에서 쓰레드 안전성이라는 것이 어떤 쓰레드가 lock 블럭을 수행 중일 때 다른 쓰레드는 대기해야 한다는 것을 의미하는 것이니까...

그렇다면, 공유데이터가 없는 쓰레드를 실행할 때는 쓰레드의 안전성은 무시해도 되는 것일까?


▣  C# Singleton Pattern 구현 - Disign pettens - 2009. 5. 14. 14:36

http://blog.naver.com/dolmoon?Redirect=Log&logNo=60051507361
 

참조 : http://www.yoda.arachsys.com/csharp/singleton.html


다음은 Windows Form을 싱글턴으로 구현한 예제


using System.Windows.Forms;

namespace SingletonSample
{
    public partial class SingletonForm : Form
    {

        //클래스 자신을 인스턴스로 저장할 멤버

        // --> 엄밀히 말하면 클래스의 유일한 인스턴스를 저장할 멤버
        private volatile static SingletonForm _singletonForm;
        //Dummy object for thread-safety
        private static object dummy = new object();

        //생성자를 감춰서 외부에서는 클래스 인스턴스를 생성할 수 없게 만듦.

        private SingletonForm()
        {
            InitializeComponent();
        }

      

        //Property형식으로 Singleton 패턴을 구현

        public static SingletonForm Instance
        {
            get
            {
                //lock은 블럭 안의 코드가 실행되는 동안 다른 쓰레드가
                //이 블럭이 실행하지 못하도록 막음(다른 쓰레드는 이 블럭이
                //완료될 때까지 기다림).
                lock(dummy)
                {

                    //_singletonForm이 static으로 선언되어 있으므로 이 클래스의 인스턴스는

                    //항상 하나만 존재하게 됨.

                    if (_singletonForm == null || _singletonForm.IsDisposed)
                        //클래스 인스턴스 생성
                        _singletonForm = new SingletonForm();
                    return _singletonForm;
                }
            }
        }

        //Method를 이용하여 Singleton 패턴을 구현
        //public static SingletonForm GetInstance()
        //{
        //    lock (dummy)
        //    {
        //        if (_singletonForm == null || _singletonForm.IsDisposed)
        //        {
        //            _singletonForm = new SingletonForm();
        //        }
        //    }
        //    return _singletonForm;
        //}
    }

  

    static class Program
    {
        [STAThread]
        private static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);


            SingletonForm form1 = SingletonForm.Instance;
            form1.Text = "First SingleForm?";
            form1.Show();
            form1.Visible = false;
            Forms.SingletonForm form2 = Forms.SingletonForm.Instance; //form1을 다시 얻어 온다.
            form2.Text += " or Second SingleForm?";
            form2.ShowDialog();
        }
    }  
}


실행해보면 form2.Text가 "First SingleForm? or Second SingleForm?"이 된다. 즉, form1과 form2는 같은 form이다.



articles
recent replies
recent trackbacks
notice
Admin : New post