2/04/2010

Replace Thread.Suspend() and Resume() method

Replace Thread.Suspend() and Resume() method
Thread Suspend() Resume() 메소드 대체하기

RiskNET Packet analysis 프로그램을 개발 중 데이터가 20만줄이 넘어가서 한번에 불러와 처리하기에는

시간이 너무 오래 걸리는 관계로 쓰레드를 사용하게 되었다.

간단하게 textbox에 있는 20만줄의 글을 ListView에 뿌려주는 일이었는데

thread 클래스를 사용중에 suspend()resume() 메소드를 사용했더니 '경고'가 뜨는것이 아닌가!?

이유는 더이상 사용하지 않는 Method... 바로  Obsolete Attribute 때문이었다.

http://msdn.microsoft.com/ko-kr/library/system.threading.thread.suspend%28VS.80%29.aspx
http://msdn.microsoft.com/ko-kr/library/system.threading.thread.resume%28VS.80%29.aspx

비록 실행은 되지만 찜찜한 기분에 이리저리 구글링을 해 보니 다음 아티클을 찾을 수 있었다.

아티클 바로가기

위 아티클에서 핵심은 아래 두 소스와 같다.

private ManualResetEvent suspendChangedEvent = new ManualResetEvent(false);
private ManualResetEvent terminateEvent = new ManualResetEvent(false);
ManualResetEvent Class는 로컬에서 신호를 보내 Event Handle을 할 수 있도록 도와준다.
이걸로 신호가 Set 되면 해당 Thread를 종료하거나 중지 또는 재시작하는 로직을 구현할 수 있게 해준다.

suspendChangedEvent.WaitOne(0, true);
terminateEvent.WaitOne(0, true);
WaitHandle.WaitAny(new WaitHandle[] { suspendChangedEvent, terminateEvent })
WaitOne method는 해당 변수가 Set 되어있으면 true를 Reset 되어있으면 false를 반환한다.
WaitHandle.WaitAny 는 주어진 매개변수중 하나라도 신호를 받을 때까지 대기한다.


아래 코드 전문은 위의 아티클에서 가져와 주석을 첨가한것이다.


소스코드
SuspendableThread.cs
namespace ThreadTest
{
    abstract public class SuspendableThread
    {
        #region Data
        private ManualResetEvent suspendChangedEvent = new ManualResetEvent(false);
        private ManualResetEvent terminateEvent = new ManualResetEvent(false);
        private long suspended;
        private Thread thread;
        private System.Threading.ThreadState failsafeThreadState = System.Threading.ThreadState.Unstarted;
        #endregion Data

        public SuspendableThread() { }

        private void ThreadEntry()
        {
            failsafeThreadState = System.Threading.ThreadState.Stopped;
            OnDoWork();
        }

        //자식클래스에서 구현할 부분 (Thread에서 돌아가는 부분)
        protected abstract void OnDoWork();

        protected Boolean SuspendIfNeeded()
        {
            Boolean suspendEventChanged = suspendChangedEvent.WaitOne(0, true);
            
            //suspendChangeEvent가 Set 되어있는 경우 실행
            if (suspendEventChanged)
            {
                Boolean needToSuspend = Interlocked.Read(ref suspended) != 0;
                suspendChangedEvent.Reset();

                //suspended 가 0이 아닌경우에만 실행
                //Suspend method실행시 suspended = 1, Resume method 실행시 suspended = 0
                if (needToSuspend)
                {
                    /// Suspending...
                    /// WaitHandle.WaitAny method: 
                    ///   주어진 매개변수들중 하나라도 신호를 받으면 신호를 받은 매개변수의 인덱스 반환
                    if (1 == WaitHandle.WaitAny(new WaitHandle[] { suspendChangedEvent, terminateEvent }))
                    {
                        //terminateEvent 변수가 신호를 받으면 true 반환
                        return true;
                    }
                    /// suspendChagedEvent 변수가 신호를 받으면 여기부터 실행
                    /// 이러한 이유로 Suspend method를 실행하면 OnDoWork method의 루프가 한번 더 실행됨
                    /// ...Waking
                }
            }
            return false;
        }

        protected bool HasTerminateRequest()
        {
            //terminateEvent가 Set이 되었으면 true 반환 Set이 안되어있으면 false 반환
            return terminateEvent.WaitOne(0, true);
        }

        public void Start()
        {
            thread = new Thread(new ThreadStart(ThreadEntry));

            // make sure this thread won't be automaticaly
            // terminated by the runtime when the
            // application exits
            thread.IsBackground = false;

            thread.Start();
        }

        public void Join()
        {
            if (thread != null)
            {
                thread.Join();
            }
        }

        public Boolean Join(Int32 milliseconds)
        {
            if (thread != null)
            {
                return thread.Join(milliseconds);
            }
            return true;
        }

        /// Not supported in .NET Compact Framework
        public Boolean Join(TimeSpan timeSpan)
        {
            if (thread != null)
            {
                return thread.Join(timeSpan);
            }
            return true;
        }

        public void Terminate()
        {
            terminateEvent.Set();
        }
        
        public void TerminateAndWait()
        {
            terminateEvent.Set();
            thread.Join();
        }

        public void Suspend()
        {
            //suspended를 1로 바꿔줌
            while (1 != Interlocked.Exchange(ref suspended, 1)) { }
            suspendChangedEvent.Set();
        }

        public void Resume()
        {
            while (0 != Interlocked.Exchange(ref suspended, 0)) { }
            suspendChangedEvent.Set();
        }

        public System.Threading.ThreadState ThreadState
        {
            get
            {
                if (null != thread)
                {
                    return thread.ThreadState;
                }
                return failsafeThreadState;
            }
        }
    }
}


SuspendableThreadWork.cs
namespace ThreadTest
{
    public class SuspendableThreadWork : SuspendableThread
    {
        public SuspendableThreadWork()
        {
        }

        protected override void OnDoWork()
        {
            try
            {
                while (false == HasTerminateRequest())
                {
                    Boolean awokenByTerminate = SuspendIfNeeded();
                    
                    if (awokenByTerminate)
                    {
                        return;
                    }
                    // TODO: replace the following to lines
                    // 코드작성
                }
            }

            finally
            {
                // TODO: Replace the following line with thread
                // exit processing.
                // 코드작성
            }
        }
    }
}


참고자료:
본문 아티클: http://msmvps.com/blogs/peterritchie/archive/2006/10/13/_2700_System.Threading.Thread.Suspend_280029002700_-is-obsolete_3A00_-_2700_Thread.Suspend-has-been-deprecated_2E002E002E00_.aspx
WaitHandle.WaitAny Method: http://msdn.microsoft.com/ko-kr/library/tdykks7z%28VS.80%29.aspx
ManualResetEvent Class: http://msdn.microsoft.com/ko-kr/library/system.threading.manualresetevent%28VS.95%29.aspx

댓글 없음:

댓글 쓰기