Thread. 앱 셧다운시 장기 수면을 중지하려면 - 더 나은 접근 방식이 있습니까?
-
16-09-2019 - |
문제
응용 프로그램 수명을 위해 실행되는 작은 배경 스레드가 있습니다. 그러나 응용 프로그램이 종료되면 스레드가 우아하게 종료되어야합니다.
문제는 스레드가 15 분 간격으로 일부 코드를 실행한다는 것입니다. 이는 많이 자고 있음을 의미합니다.
이제 잠을 자지 않기 위해 인터럽트를 던지기 위해서는 인터럽트가 스레드 인터럽트를 생성하기 때문에 더 나은 접근 방식이 있다면 내 질문입니다.
다음은 내 코드의 요점입니다 (다소 의사) :
public class BackgroundUpdater : IDisposable
{
private Thread myThread;
private const int intervalTime = 900000; // 15 minutes
public void Dispose()
{
myThread.Interrupt();
}
public void Start()
{
myThread = new Thread(ThreadedWork);
myThread.IsBackground = true; // To ensure against app waiting for thread to exit
myThread.Priority = ThreadPriority.BelowNormal;
myThread.Start();
}
private void ThreadedWork()
{
try
{
while (true)
{
Thread.Sleep(900000); // 15 minutes
DoWork();
}
}
catch (ThreadInterruptedException)
{
}
}
}
해결책
더 나은 방법이 절대적으로 있습니다 Monitor.Wait
/맥박 수면/인터럽트 대신에 사용하십시오 Auto
/ManualResetEvent
. (아마도 원할 것입니다 ManualResetEvent
이 경우.)
개인적으로 나는 대기/펄스 팬 일 것입니다. 아마도 Java 's Wait ()/notify () 메커니즘과 같기 때문일 것입니다. 그러나 재설정 이벤트가 더 유용한 경우가 있습니다.
코드는 다음과 같이 보입니다.
private readonly object padlock = new object();
private volatile bool stopping = false;
public void Stop() // Could make this Dispose if you want
{
stopping = true;
lock (padlock)
{
Monitor.Pulse(padlock);
}
}
private void ThreadedWork()
{
while (!stopping)
{
DoWork();
lock (padlock)
{
Monitor.Wait(padlock, TimeSpan.FromMinutes(15));
}
}
}
자세한 내용은 내 것을 참조하십시오 스레딩 튜토리얼, 특히 페이지가 있습니다 교착 상태, 대기 및 맥동, 페이지 켜짐 대기 핸들. 조 알바 하리 또한 튜토리얼이 있습니다 동일한 주제를 다루고 비교합니다.
나는 아직 자세히 보지 못했지만 병렬 확장이 이것을 더 쉽게 할 수있는 기능이 있다면 놀라지 않을 것입니다.
다른 팁
이벤트를 사용하여 프로세스가 다음과 같이 끝나야하는지 확인할 수 있습니다.
var eventX = new AutoResetEvent(false);
while (true)
{
if(eventX.WaitOne(900000, false))
{
break;
}
DoWork();
}
거기 있습니다 CancellationTokenSource
.NET 4 이상의 클래스는이 작업을 약간 단순화합니다.
private readonly CancellationTokenSource cancellationTokenSource =
new CancellationTokenSource();
private void Run()
{
while (!cancellationTokenSource.IsCancellationRequested)
{
DoWork();
cancellationTokenSource.Token.WaitHandle.WaitOne(
TimeSpan.FromMinutes(15));
}
}
public void Stop()
{
cancellationTokenSource.Cancel();
}
그것을 잊지 마세요 CancellationTokenSource
일회용이므로 제대로 처리하십시오.
한 가지 방법은 취소 이벤트를 추가하거나 스레드가 구독 할 위임입니다. 취소 이벤트가 호출되면 스레드가 스스로 중지 될 수 있습니다.
나는 Jon Skeets 대답을 절대적으로 좋아합니다. 그러나 이것 ~할 것 같다 이해하기가 조금 더 쉽고 작동해야합니다.
public class BackgroundTask : IDisposable
{
private readonly CancellationTokenSource cancellationTokenSource;
private bool stop;
public BackgroundTask()
{
this.cancellationTokenSource = new CancellationTokenSource();
this.stop = false;
}
public void Stop()
{
this.stop = true;
this.cancellationTokenSource.Cancel();
}
public void Dispose()
{
this.cancellationTokenSource.Dispose();
}
private void ThreadedWork(object state)
{
using (var syncHandle = new ManualResetEventSlim())
{
while (!this.stop)
{
syncHandle.Wait(TimeSpan.FromMinutes(15), this.cancellationTokenSource.Token);
if (!this.cancellationTokenSource.IsCancellationRequested)
{
// DoWork();
}
}
}
}
}
또는 배경 작업이 실제로 중지되기를 기다리는 것을 포함하여 (이 경우, 배경 스레드가 실행되는 것보다 다른 스레드에 의해 폐기되어야하며, 물론 이것은 완벽한 코드가 아니므로 작업자 스레드가 실제로 필요합니다. 시작했다):
using System;
using System.Threading;
public class BackgroundTask : IDisposable
{
private readonly ManualResetEventSlim threadedWorkEndSyncHandle;
private readonly CancellationTokenSource cancellationTokenSource;
private bool stop;
public BackgroundTask()
{
this.threadedWorkEndSyncHandle = new ManualResetEventSlim();
this.cancellationTokenSource = new CancellationTokenSource();
this.stop = false;
}
public void Dispose()
{
this.stop = true;
this.cancellationTokenSource.Cancel();
this.threadedWorkEndSyncHandle.Wait();
this.cancellationTokenSource.Dispose();
this.threadedWorkEndSyncHandle.Dispose();
}
private void ThreadedWork(object state)
{
try
{
using (var syncHandle = new ManualResetEventSlim())
{
while (!this.stop)
{
syncHandle.Wait(TimeSpan.FromMinutes(15), this.cancellationTokenSource.Token);
if (!this.cancellationTokenSource.IsCancellationRequested)
{
// DoWork();
}
}
}
}
finally
{
this.threadedWorkEndSyncHandle.Set();
}
}
}
Jon Skeets 솔루션에 대한 결함과 단점이 있으면 항상 학습을 즐기기 때문에 듣고 싶습니다. ;-) 나는 이것이 더 느리고 더 많은 메모리를 사용하여 대규모 및 짧은 기간으로 사용해서는 안된다고 생각합니다. 다른 사람?