スレッドで、いくつかの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
が推奨されない理由の1つです。何よりもまず、Thread.Abort()
を使用して、可能な限りスレッドをキャンセルまたは停止しないでください。Abort()
は、タイムリーに停止するためのより平和的な要求に対応する。
つまり、一方のスレッドが定期的にチェックして正常に終了する間、一方のスレッドが設定して待機する共有キャンセルインジケーターを提供する必要があります。 .NET 4には、この目的のために特別に設計された構造 CancellationToken
が含まれています。
これを直接やろうとしないでください。 CancellationToken で動作するようにタスクを設計し、この方法でキャンセルします。
さらに、CancelationToken経由でも機能するようにメインスレッドを変更することをお勧めします。 Thread.Abort()
を呼び出すのは悪い考えです。診断が非常に難しいさまざまな問題につながる可能性があります。代わりに、そのスレッドは、タスクが使用するのと同じ キャンセル を使用できます。また、同じCancellationTokenSource
を使用して、allタスクとメインスレッド。
これにより、はるかにシンプルで安全な設計が可能になります。
Task.Factory.StartNew()で匿名メソッドを使用しないときにCancellationTokensを使用する方法に関するPrerak Kの質問に答えるには、MSDNの例に示すように、StartNew()で開始するメソッドにパラメーターとして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
が役立ちます。後者の場合は、おそらく独自の「救済」メカニズムを実装し、タスク実行の適切な時点で高速に失敗するかどうかを確認する必要があります(CancelationTokenを使用して手伝ってもかまいませんが、もう少し手作業です)。
MSDNには、タスクのキャンセルに関する記事があります。 http://msdn.Microsoft.com/en-us/library/dd997396.aspx
タスクはThreadPoolで実行されているため(少なくとも、デフォルトのファクトリを使用している場合)、スレッドを中止してもタスクに影響はありません。タスクの中止については、msdnの Task Cancellation を参照してください。
タスクには キャンセルトークン によるキャンセルのファーストクラスサポートがあります。キャンセルトークンを使用してタスクを作成し、これらを明示的に介してタスクをキャンセルします。
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();
}
}
}