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
댓글 없음:
댓글 쓰기