스레드에서 일부 System.Threading.Task
작업을 만들고 각 작업을 시작합니다.
.Abort()
스레드를 죽이려고 할 때 작업이 중단되지 않습니다.
.Abort()
내 작업에 어떻게 전송 합니까?
답변
당신은 할 수 없습니다. 작업은 스레드 풀의 백그라운드 스레드를 사용합니다. 또한 Abort 메서드를 사용하여 스레드를 취소하지 않는 것이 좋습니다. 취소 토큰을 사용하여 작업을 취소하는 적절한 방법을 설명하는 다음 블로그 게시물 을 살펴볼 수 있습니다 . 예를 들면 다음과 같습니다.
class Program
{
static void Main()
{
var ts = new CancellationTokenSource();
CancellationToken ct = ts.Token;
Task.Factory.StartNew(() =>
{
while (true)
{
// do some heavy work here
Thread.Sleep(100);
if (ct.IsCancellationRequested)
{
// another thread decided to cancel
Console.WriteLine("task canceled");
break;
}
}
}, ct);
// Simulate waiting 3s for the task to complete
Thread.Sleep(3000);
// Can't wait anymore => cancel this task
ts.Cancel();
Console.ReadLine();
}
}
답변
작업이 실행중인 스레드를 캡처하면 작업을 중단 할 수 있습니다. 다음은이를 보여주는 예제 코드입니다.
void Main()
{
Thread thread = null;
Task t = Task.Run(() =>
{
//Capture the thread
thread = Thread.CurrentThread;
//Simulate work (usually from 3rd party code)
Thread.Sleep(1000);
//If you comment out thread.Abort(), then this will be displayed
Console.WriteLine("Task finished!");
});
//This is needed in the example to avoid thread being still NULL
Thread.Sleep(10);
//Cancel the task by aborting the thread
thread.Abort();
}
필자는 Task.Run ()을 사용하여 가장 일반적인 유스 케이스를 보여주었습니다. 취소 여부를 결정하기 위해 CancellationTokenSource 클래스를 사용하지 않는 오래된 단일 스레드 코드가있는 작업의 편의를 사용했습니다.
답변
마찬가지로 이 게시물 제안, 이것은 다음과 같은 방법으로 수행 할 수 있습니다 :
int Foo(CancellationToken token)
{
Thread t = Thread.CurrentThread;
using (token.Register(t.Abort))
{
// compute-bound work here
}
}
작동하지만 그러한 방법을 사용하지 않는 것이 좋습니다. 작업에서 실행되는 코드를 제어 할 수 있으면 적절한 취소 처리를 수행하는 것이 좋습니다.
답변
이런 종류의 일은 왜 Abort
더 이상 사용되지 않는 물류상의 이유 중 하나입니다 . 우선, 가능하면 스레드를 취소하거나 중지하는 데 사용하지 마십시오 Thread.Abort()
. Abort()
적시에 중지하라는보다 평화로운 요청에 응답하지 않는 스레드를 강제로 종료하는 데만 사용해야합니다.
즉, 한 스레드가 설정하고 대기하는 동안 다른 스레드가 주기적으로 확인하고 정상적으로 종료되는 공유 취소 표시기를 제공해야합니다. .NET 4에는이 목적을 위해 특별히 설계된 구조가 포함되어 CancellationToken
있습니다.
답변
직접 시도하지 마십시오. CancellationToken 과 함께 작동하도록 작업을 설계하십시오. 하고이 방법으로 취소하십시오.
또한 CancellationToken을 통해 기본 스레드를 작동하도록 변경하는 것이 좋습니다. 전화 Thread.Abort()
하는 것은 나쁜 생각입니다. 진단하기가 매우 어려운 다양한 문제가 발생할 수 있습니다. 대신, 해당 스레드는 작업에서 사용하는 것과 동일한 취소 를 사용할 CancellationTokenSource
수 있으며 모든 작업 및 기본 스레드 의 취소를 트리거하는 데 사용될 수 있습니다 .
이것은 훨씬 더 단순하고 안전한 디자인으로 이어질 것입니다.
답변
Task.Factory.StartNew ()에서 익명 메서드를 사용하지 않을 때 CancellationTokens를 사용하는 방법에 대한 Prerak K의 질문에 대답하기 위해 MSDN 예제에 표시된 것처럼 CancellationToken을 StartNew ()로 시작하는 메서드에 매개 변수로 전달합니다. 여기 .
예 :
var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
Task.Factory.StartNew( () => DoSomeWork(1, token), token);
static void DoSomeWork(int taskNum, CancellationToken ct)
{
// Do work here, checking and acting on ct.IsCancellationRequested where applicable,
}
답변
작업을 취소하기 위해 혼합 접근법을 사용합니다.
- 첫째, 나는 사용하여 정중를 취소하기 위해 노력하고있어 예약 취소 .
- 여전히 실행 중이면 (예 : 개발자의 실수로 인해) 구식 Abort 메소드를 사용하여 오작동하고 종료 합니다.
아래 예를 확인하십시오.
private CancellationTokenSource taskToken;
private AutoResetEvent awaitReplyOnRequestEvent = new AutoResetEvent(false);
void Main()
{
// Start a task which is doing nothing but sleeps 1s
LaunchTaskAsync();
Thread.Sleep(100);
// Stop the task
StopTask();
}
/// <summary>
/// Launch task in a new thread
/// </summary>
void LaunchTaskAsync()
{
taskToken = new CancellationTokenSource();
Task.Factory.StartNew(() =>
{
try
{ //Capture the thread
runningTaskThread = Thread.CurrentThread;
// Run the task
if (taskToken.IsCancellationRequested || !awaitReplyOnRequestEvent.WaitOne(10000))
return;
Console.WriteLine("Task finished!");
}
catch (Exception exc)
{
// Handle exception
}
}, taskToken.Token);
}
/// <summary>
/// Stop running task
/// </summary>
void StopTask()
{
// Attempt to cancel the task politely
if (taskToken != null)
{
if (taskToken.IsCancellationRequested)
return;
else
taskToken.Cancel();
}
// Notify a waiting thread that an event has occurred
if (awaitReplyOnRequestEvent != null)
awaitReplyOnRequestEvent.Set();
// If 1 sec later the task is still running, kill it cruelly
if (runningTaskThread != null)
{
try
{
runningTaskThread.Join(TimeSpan.FromSeconds(1));
}
catch (Exception ex)
{
runningTaskThread.Abort();
}
}
}