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