몇 가지 좋은 제안이 있지만 기본적인 문제를 해결할 수 있다고 생각하지 않습니다. 배경 작업을 취소하는 것입니다.
private readonly BackgroundWorker worker = new BackgroundWorker();
public void SomeFormEventForStartingBackgroundTask()
{
worker.DoWork += BackgroundTask_HotelCalifornia;
worker.WorkerSupportsCancellation = true;
worker.RunWorkerAsync();
}
// semantically, you want to perform this task for lifetime of
// application, you may even expect that calling CancelAsync
// will out and out abort this method - that is incorrect.
// CancelAsync will only set DoWorkEventArgs.Cancel property
// to true
private void BackgroundTask_HotelCalifornia (object sender, DoWorkEventArgs e)
{
for (; ;)
{
// because we never inspect e.Cancel, we can never leave!
}
}
private void App_FormClosing(object sender, FormClosingEventArgs e)
{
// [politely] request termination
worker.CancelAsync();
// [politely] wait until background task terminates
while (worker.IsBusy);
}
고려하십시오. 자, 아마도 당신의 작업은 무한 루프가 아니며 아마도 장기 실행 작업 일 것입니다. 어느 쪽이든, 주 스레드는 작업이 완료 될 때까지 [실제로 회전하고 있지만 whatevs] 차단하거나 경우에 따라 그렇지 않습니다.
개인적으로 글을 쓰고 작업을 수정할 수있는 경우 몇 가지 옵션이 있습니다.
예 개선
는 예를 들어, 이것은이 더 있지만, 그것은 수만큼 좋지 않아 위의 예
private readonly BackgroundWorker worker = new BackgroundWorker();
// this is used to signal our main Gui thread that background
// task has completed
private readonly AutoResetEvent isWorkerStopped =
new AutoResentEvent (false);
public void SomeFormEventForStartingBackgroundTask()
{
worker.DoWork += BackgroundTask_HotelCalifornia;
worker.RunWorkerCompleted += BackgroundTask_Completed;
worker.WorkerSupportsCancellation = true;
worker.RunWorkerAsync();
}
private void BackgroundTask_HotelCalifornia (object sender, DoWorkEventArgs e)
{
// execute until canceled
for (; !e.Cancel;)
{
// keep in mind, this task will *block* main
// thread until cancel flag is checked again,
// so if you are, say crunching SETI numbers
// here for instance, you could still be blocking
// a long time. but long time is better than
// forever ;)
}
}
private void BackgroundTask_Completed (
object sender,
RunWorkerCompletedEventArgs e)
{
// ok, our task has stopped, set signal to 'signaled' state
// we are complete!
isStopped.Set();
}
private void App_FormClosing(object sender, FormClosingEventArgs e)
{
// [politely] request termination
worker.CancelAsync();
// [politely] wait until background task terminates
isStopped.WaitOne();
}
의 더 나은 구현입니다. 배경 작업이 끝날 것이라고 [합리적으로] 확신 할 수 있다면 "충분히 좋다"고 할 수 있습니다.
그러나, 우리는 [보통] 원하는, 우리는 할 수없는이
private void App_FormClosing(object sender, FormClosingEventArgs e)
{
// [politely] request termination
worker.CancelAsync();
// [politely] wait until background task terminates
TimeSpan gracePeriod = TimeSpan.FromMilliseconds(100);
bool isStoppedGracefully = isStopped.WaitOne (gracePeriod);
if (!isStoppedGracefully)
{
// KILL! KILL! KILL!
}
}
아아 같은 것입니다. BackgroundWorker
은 강제 종료의 수단을 노출하지 않습니다. 이는 숨겨진 스레드 관리 시스템 위에 구축 된 추상화이기 때문에 강제 종료되는 경우 응용 프로그램의 다른 부분을 잠재적으로 비화시킬 수 있습니다.
위의 내용을 구현하는 유일한 방법은 자신의 스레딩을 관리하는 것입니다.
예 이상적인
그래서, 예를
private Thread worker = null;
// this time, 'Thread' provides all synchronization
// constructs required for main thread to synchronize
// with background task. however, in the interest of
// giving background task a chance to terminate gracefully
// we supply it with this cancel signal
private readonly AutoResetEvent isCanceled = new AutoResentEvent (false);
public void SomeFormEventForStartingBackgroundTask()
{
worker = new Thread (BackgroundTask_HotelCalifornia);
worker.IsBackground = true;
worker.Name = "Some Background Task"; // always handy to name things!
worker.Start();
}
private void BackgroundTask_HotelCalifornia()
{
// inspect cancel signal, no wait period
//
// NOTE: so cheating here a bit, this is an instance variable
// but could as easily be supplied via parameterized thread
// start delegate
for (; !isCanceled.WaitOne (0);)
{
}
}
private void App_FormClosing(object sender, FormClosingEventArgs e)
{
// [politely] request termination
isCanceled.Set();
// [politely] wait until background task terminates
TimeSpan gracePeriod = TimeSpan.FromMilliseconds(100);
bool isStoppedGracefully = worker.Join (gracePeriod);
if (!isStoppedGracefully)
{
// wipe them out, all of them.
worker.Abort();
}
}
그리고 거기에 대한, 스레드 관리에 괜찮은 소개합니다.
어떤 것이 가장 적합합니까? 귀하의 신청서에 따라 다릅니다. 그것은 보트 바위, 그리고
- 당신의 배경 작업이 검사 수 있도록 현재의 구현을 수정하는 것이 가장 하지하고 폴링
반대로, 완료의
Cancel
재산
- 주 스레드 대기를 존중
각 접근법의 장단점을 비교하고 평가하는 것이 매우 중요합니다.
경우 해야 다른 사람의 작업 제어 및 보증 종료 후 갈 수있는 방법이 될 수 있습니다 위의 통합 스레드 관리 시스템을 쓰기. 그러나 스레드 풀링, 진행률보고, 스레드 간 데이터 마샬링 [작업자는 그럴 수 있습니까?] 및 기타 여러 가지 기능과 같은 기본 기능을 사용하지 못하게됩니다. 말할 것도없이, "자신 만의 롤링"은 종종 오류가 발생하기 쉽습니다. 어쨌든
이 도움이 :)
당신은 다음과 같이 회전 폴링 루프를 실행해서는 안됩니다, 그것은 CPU 사이클이 작업을 완료하려면 다른 스레드가 어려워 소비를 바랍니다. WaitHandle 또는 유사한 동기화 프리미티브를 사용할 수없고 절대적으로 폴링해야한다면 Thread.Sleep (x)를 거기에 추가하십시오. –
+1을 @ Hightechrider 님의 의견입니다. 응용 프로그램이 종료되지 않을뿐만 아니라 잠자기 시간이 없으면 전체 시스템이 잠 깁니다. –
경우에 따라서는 BackgroundWorker에 대해 CanBeCancel 또는 so 속성을 true로 설정 했습니까? –