스레드에서 일부 System.Threading.Task
작업을 만들고 각 작업을 시작합니다.
.Abort()
스레드를 죽이려고 할 때 작업이 중단되지 않습니다.
.Abort()
내 작업에 어떻게 전송 합니까?
스레드에서 일부 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();
}
}
Task.Wait(TimeSpan / int)
외부에서 (시간 기반) 마감일을주는 것입니다.
Task
됩니까? 같은 것 : public int StartNewTask(Action method)
. 내부 StartNewTask
방법을 나는 새를 생성 Task
하여 : Task task = new Task(() => method()); task.Start();
. 그래서 어떻게 관리 할 수 CancellationToken
있습니까? 또한 Thread
여전히 걸려있는 일부 작업이 있는지 확인하기 위해 논리를 구현 해야하는지 알고 싶습니다 Form.Closing
. 와 함께 Threads
사용 Thread.Abort()
합니다.
작업이 실행중인 스레드를 캡처하면 작업을 중단 할 수 있습니다. 다음은이를 보여주는 예제 코드입니다.
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 클래스를 사용하지 않는 오래된 단일 스레드 코드가있는 작업의 편의를 사용했습니다.
CancellationToken
CancellationToken
경쟁 조건이없는 간단한 솔루션도 고려해야합니다. 위의 코드는 사용 영역이 아니라 방법 만 설명합니다.
thread
로컬 변수 로 전달됨을 의미 함 ). 코드에서 메인 스레드를 중단시킬 수 있습니다. 실제로 원하는 것은 아닙니다. 중단을 주장하는 경우 중단이 발생하기 전에 스레드가 동일한 지 확인하는 것이 좋습니다.
마찬가지로 이 게시물 제안, 이것은 다음과 같은 방법으로 수행 할 수 있습니다 :
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,
}
작업을 취소하기 위해 혼합 접근법을 사용합니다.
아래 예를 확인하십시오.
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();
}
}
}
a CancellationToken
를 사용 하여 작업 취소 여부를 제어 할 수 있습니다 . 시작하기 전에 중단하거나 (이미이 작업을 수행 했음) 실제로 중단하는 것에 대해 이야기하고 있습니까? 전자의 경우 CancellationToken
도움 이 될 수 있습니다. 후자의 경우 아마도 "베일 아웃"메커니즘을 구현하고 작업 실행의 적절한 지점에서 빠르게 실패해야하는지 여부를 확인해야합니다 (여전히 도움을주기 위해 CancellationToken을 사용할 수는 있지만 조금 더 수동적 임).
MSDN에는 작업 취소에 대한 기사가 있습니다. http://msdn.microsoft.com/en-us/library/dd997396.aspx
나는 시도 CancellationTokenSource
했지만 이것을 할 수 없다. 그리고 나는 내 자신의 방식으로 이것을했습니다. 그리고 작동합니다.
namespace Blokick.Provider
{
public class SignalRConnectProvider
{
public SignalRConnectProvider()
{
}
public bool IsStopRequested { get; set; } = false; //1-)This is important and default `false`.
public async Task<string> ConnectTab()
{
string messageText = "";
for (int count = 1; count < 20; count++)
{
if (count == 1)
{
//Do stuff.
}
try
{
//Do stuff.
}
catch (Exception ex)
{
//Do stuff.
}
if (IsStopRequested) //3-)This is important. The control of the task stopping request. Must be true and in inside.
{
return messageText = "Task stopped."; //4-) And so return and exit the code and task.
}
if (Connected)
{
//Do stuff.
}
if (count == 19)
{
//Do stuff.
}
}
return messageText;
}
}
}
그리고 메소드 호출의 또 다른 클래스 :
namespace Blokick.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MessagePerson : ContentPage
{
SignalRConnectProvider signalR = new SignalRConnectProvider();
public MessagePerson()
{
InitializeComponent();
signalR.IsStopRequested = true; // 2-) And this. Make true if running the task and go inside if statement of the IsStopRequested property.
if (signalR.ChatHubProxy != null)
{
signalR.Disconnect();
}
LoadSignalRMessage();
}
}
}
당신이 작업이 자신의 스레드에서 생성의 원인이 될 수 있고, 호출 할 경우 스레드와 같은 작업을 중단 할 수 있습니다 Abort
에의Thread
개체를 . 기본적으로 작업은 스레드 풀 스레드 또는 호출 스레드에서 실행되며 일반적으로 중단하지 않습니다.
작업이 자체 스레드를 갖도록하려면에서 파생 된 사용자 지정 스케줄러를 만듭니다 TaskScheduler
. 의 구현 QueueTask
에서 새 스레드를 작성하고이를 사용하여 태스크를 실행하십시오. 나중에 스레드를 중단하면 작업이 오류 상태에서 완료됩니다 ThreadAbortException
.
이 작업 스케줄러를 사용하십시오.
class SingleThreadTaskScheduler : TaskScheduler
{
public Thread TaskThread { get; private set; }
protected override void QueueTask(Task task)
{
TaskThread = new Thread(() => TryExecuteTask(task));
TaskThread.Start();
}
protected override IEnumerable<Task> GetScheduledTasks() => throw new NotSupportedException(); // Unused
protected override bool NotSupportedException(Task task, bool taskWasPreviouslyQueued) => throw new NotSupportedException(); // Unused
}
다음과 같이 작업을 시작하십시오.
var scheduler = new SingleThreadTaskScheduler();
var task = Task.Factory.StartNew(action, cancellationToken, TaskCreationOptions.LongRunning, scheduler);
나중에 다음과 같이 중단 할 수 있습니다.
scheduler.TaskThread.Abort();
점을 유의 스레드를 중단에 대한 경고가 계속 적용 :
이
Thread.Abort
방법은주의해서 사용해야합니다. 특히 현재 스레드 이외의 스레드를 중단하기 위해 호출 할 때 ThreadAbortException 이 발생 했을 때 어떤 코드가 실행되었거나 실행되지 않았는지 알 수 없으며 응용 프로그램의 상태 또는 응용 프로그램 및 사용자 상태를 확실하게 알 수 없습니다 보존 책임이 있습니다. 예를 들어 호출Thread.Abort
하면 정적 생성자가 실행되지 못하게하거나 관리되지 않는 리소스가 해제되지 않을 수 있습니다.
Thread.Abort
.NET Core에서 지원되지 않는다는 것입니다 . 이를 사용하려고하면 예외가 발생합니다. System.PlatformNotSupportedException :이 플랫폼에서는 스레드 중단이 지원되지 않습니다. 세 번째 경고는 SingleThreadTaskScheduler
약속 스타일 작업, 즉 async
대의원으로 만든 작업에서 효과적으로 사용할 수 없다는 것 입니다. 예를 들어 임베디드 await Task.Delay(1000)
는 스레드없이 실행되므로 스레드 이벤트에는 영향을 미치지 않습니다.