앱 실행 화면
"Start Worker"버튼을 눌러써 BackgroundWorker를 동작시킨 후,
Cancel Worker,Cancel Worker(Timer)버튼을 선택 했을 때,진행 중인 작업을
취소하는 과정을 확인해 보겠습니다.
keyword
1. BackgroundWorker CancelASync
2. BackgroundWorker CancelASync 동작 확인 - 버튼
3. BackgroundWorker CancelASync 동작 확인 - 타이머
BackgroundWorker CancelAsync
작업스레드의 내용이 프로그래스바 진행사항 표시 라고 할때, 100퍼센트까지 수행 되면 코드루틴은 완료 되고, RunWorkerCompleted이벤트핸들러가 수행 되어 BackgroundWorker관련 작업은 종료하게 됩니다.
반면 작업스레드의 내용이 특정 시간동안만 수행되는 경우,
또는 모니터링 하다가 특정 상황이되어 작업을 종료 하는 경우 등은
작업스레드의 내용을 명시적으로 취소(Cancel)해야 합니다.
File : Form1.cs
void worker_DoWork(object sender, DoWorkEventArgs e)
{
//This is Worker Thread
string argument = e.Argument as string;
Debug.WriteLine(string.Format("Worker Start:{0}",e.Argument));
try
{
switch (argument)
{
case "REPORT":
{
//작업스레드 동작중 Cancel을 고려한 부분에서
//CancellationPending값 체크를 위해 별도 로직 추가(workerCancelCheck메서드)
//아래 부분은 CancelAsync에 의해 취소 될 수 있는 부분
for (int i = 20; i <= 100; i+=20)
{
if (!workerCancelCheck(e))
{
worker.ReportProgress(i);
Thread.Sleep(1000);
Thread.Sleep(1000);
}else
{
Debug.WriteLine(string.Format("Cancel Loop : {0}",e.Cancel));
break;
}
}
Debug.WriteLine(string.Format("Hello Code"));
break;
}
default:
break;
}
}
catch (Exception ex)
{
Debug.WriteLine(string.Format("Full Stacktrace: {0}", ex.ToString()));
}
}
}
public bool workerCancelCheck(DoWorkEventArgs e)
{
bool retValue = false;
//CancellationPending속성 값을 체크
//cancelASync()을 호출하면 CancellationPending이 True로 변경
if (worker.CancellationPending == true)
{
e.Cancel = true;
retValue = true;
}
return retValue;
}
작업스레드에서 동작 취소(Cancel)가 필요한 코드 블럭에 CancellationPending값을 체크하는 로직을 추가 합니다.
workerCanclCheck메서드가 해당용도로 제작 되어졌습니다.
이제 "Cancel Worker"버튼을 눌러 작업스레드를 취소하도록 하겠습니다.
File : Form1.cs
private void cmdCancel_Click(object sender, EventArgs e)
{
_worker.cancelASync();
}
File : CDeligateWorker.cs
public void cancelASync()
{
//BackgroundWorker Class의 CancelAsync를 호출한다.
worker.CancelAsync();
}
버튼이 눌러졌을 때 CancelAsync를 호출하고 CancelAsync메서드는
내부적으로 CancellationPending속성을 True로 설정 합니다.
for (int i = 20; i <= 100; i+=20)
{
if (!workerCancelCheck(e))
{
worker.ReportProgress(i);
Thread.Sleep(1000);
Thread.Sleep(1000);
}else
{
Debug.WriteLine(string.Format("Cancel Loop : {0}",e.Cancel));
break;
}
}
Debug.WriteLine(string.Format("Hello Code"));
프로그래스가바가 업데이트중에 "Cancel Work"을 누르면 위 코드에서
workerCancelCheck에서 true값이 전달 되어 Debug.WriteLine(string.Format("Cancel Loop : {0}",e.Cancel))을
수행하여 for-loop을 종료 합니다.
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//This is UI Thread
Debug.WriteLine(string.Format("Worker Complete:{0}", e.Cancelled));
try
{
if (!e.Cancelled)
{
System.Windows.Forms.MessageBox.Show("BackgroundWorker Complete",
"Message",
System.Windows.Forms.MessageBoxButtons.OK,
System.Windows.Forms.MessageBoxIcon.Information);
_progressform.Close();
_uiManager.resetButton();
}
else
{
System.Windows.Forms.MessageBox.Show("BackgroundWorker Canceled",
"Message",
System.Windows.Forms.MessageBoxButtons.OK,
System.Windows.Forms.MessageBoxIcon.Information);
_progressform.Close();
_uiManager.resetButton();
}
}
catch (Exception ex)
{
Debug.WriteLine(string.Format("Full Stacktrace: {0}", ex.ToString()));
}
}
작업스레드는 작업이 완료될 때, 그리고 작업이 취소될때 2가지의 경우를
가지고 종료가 된다. "Cancel Worker"버튼을 눌렀을 때 CancelAsync
메서드를 호출하고, 이 메서드에 의해 CancellationPending이 True로
설정됩니다. 그리고, workerCancelCheck함수내부에서 CancellationPending이 True이면, e.Cancel = true로 설정 됩니다.
그리고 작업스레드가 종료되고 worker_RunWorkerCompleted이 수행될 때
두 번째 인자값으로 전달된 e파라미터에 e.Cancel을 포함하고 있습니다.
void worker_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
따라서 worker_RunWorkerCompleted가 수행될때 해당 이벤트 핸들러
안에서는 if (!e.Cancelled)코드를 사용해서, 작업스레드가 정상적으로
종료되었는지 Cancel인지 구분해서 필요한 작업을 할 수 있습니다.
프로그래스바가 40%쯤 진행되었을 때, Cancel Worker버튼을 누르면
프로그래스바가 업데이트가 중지되고,worker_RunWorkerCompleted
이벤트 핸들러에서 e.Cancelled 값을 체크항여 현재 작업스레드의 종료
상태를 메시지 박스를 통해 보여주고 있습니다.
3.BackgroundWorker CancelASync 동작 확인 - 타이머
Timer에 의해 작업스레드가 취소되는 형태를 확인해 보겠습니다.
"2. BackgroundWorker CancelASync 동작 확인 - 버튼"에서 필요한
내용은 모두 확인을 했고, 여기에서는 Timer사용법에 대해서만 추가하도록
하겠습니다.
file : Form1.cs
//"Cancel Worker(Timer)"버튼을 눌렀을 때 실행
private void cmdCancelTimer_Click(object sender, EventArgs e)
{
int duration = 2; //인자는 초를 의미. 2는 2초를 의미
_worker.startCancelTimer(duration);
}
File : CDiligentWorker.cs
System.Timers.Timer _finishTimer; //Timer 데이터 멤버선언
public void startCancelTimer(int durationSec)
{
//Timer설정
_finishTimer = new System.Timers.Timer();
//인자X1000을 해서. 초단위로 변환.기본적으로는 msec단위
_finishTimer.Interval = durationSec * 1000;
//2초는 수행되는 Handler등록
_finishTimer.Elapsed += FinishTimer_Elapsed;
//Timer Start
_finishTimer.Start();
//Timer시작시간 디버깅목적
DateTime taskStartTime = System.DateTime.Now;
string s_startTime = string.Format(
"{0:hh:mm:ss tt}",
taskStartTime);
Debug.WriteLine(string.Format(
"Timer START Time(Vaccine) :{0}",
s_startTime));
}
private void FinishTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (_finishTimer != null)
{
if (_finishTimer.Enabled)
{
_finishTimer.Stop();
//Timer동작 시간 디버깅 용도.
DateTime tasEndTime = System.DateTime.Now;
string s_EndTime = string.Format("{0:hh:mm:ss tt}", tasEndTime);
System.Diagnostics.Debug.WriteLine(string.Format("Timer Finish Time(Vaccine) :{0}", s_EndTime));
}
}
worker.CancelAsync();
}
startCancelTimer을 통해 Timer를 등록하고,Timer Expire시간
(여기서는 2초)이 지나면 FinishTimer_Elapsed이 실행 됩니다.
해당 메서드애세 worker.CancelAsync()를 호출하여 작업스레드를 Cancel
하는 작업을 수행 합니다.