回答:
できません。タスクはスレッドプールのバックグラウンドスレッドを使用します。また、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クラスを使用せずにキャンセルする必要があるかどうかを判断しない古いシングルスレッドコードでTasksの快適さを使用しています。
CancellationToken
サポートされていない外部コードのタイムアウトを実装しました...
CancellationToken
競合状態のない、より簡単なソリューションを検討する必要があります。上記のコードは、使用方法の領域ではなく、メソッドのみを示しています。
thread
ローカル変数に渡されます)。あなたのコードでは、メインスレッドをアボートすることになるかもしれませんが、それはあなたが本当に望んでいることではありません。おそらく、中止を主張する場合、中止前にスレッドが同じであるかどうかを確認することをお勧めします。
同じように、この記事が示唆する、これは次のように行うことができます。
int Foo(CancellationToken token)
{
Thread t = Thread.CurrentThread;
using (token.Register(t.Abort))
{
// compute-bound work here
}
}
動作しますが、そのようなアプローチを使用することは推奨されません。タスクで実行されるコードを制御できる場合は、キャンセルを適切に処理することをお勧めします。
このようなことは、Abort
が廃止される理由の1つです。何よりもまず、可能な限りスレッドをキャンセルまたは停止するためにを使用しないでくださいThread.Abort()
。 Abort()
タイムリーに停止するというより平和的な要求に応答していないスレッドを強制的に強制終了するためにのみ使用してください。
とはいえ、他のスレッドが定期的にチェックして正常に終了する間、1つのスレッドが設定して待機する共有キャンセルインジケーターを提供する必要があります。.NET 4には、この目的のために特別に設計された構造が含まれていCancellationToken
ます。
これを直接行わないでください。CancellationTokenと連携するようにタスクを設計するこの方法でキャンセルします。
さらに、CancellationTokenを介して機能するようにメインスレッドを変更することもお勧めします。呼び出しThread.Abort()
は悪い考えです-診断するのが非常に難しいさまざまな問題を引き起こす可能性があります。代わりに、そのスレッドは、タスクが使用するのと同じキャンセルを使用できます。また、同じスレッドを使用してCancellationTokenSource
、すべてのタスクとメインスレッドのキャンセルをトリガーできます。
これにより、はるかにシンプルで安全な設計が可能になります。
Task.Factory.StartNew()で匿名メソッドを使用しない場合のCancellationTokensの使用方法に関するPrerak Kの質問に回答するには、MSDNの例に示すように、Startlation()で開始するメソッドにパラメーターとしてCancellationTokenを渡します。ここに。
例えば
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();
}
}
}
を使用し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:スレッドの中止は、このプラットフォームではサポートされていません。3つ目の注意点は、SingleThreadTaskScheduler
promiseスタイルのタスク、つまりasync
デリゲートで作成されたタスクではを効果的に使用できないことです。たとえば、埋め込みawait Task.Delay(1000)
はスレッドなしで実行されるため、スレッドイベントの影響を受けません。