Bir iş parçacığında, bazı oluşturmak System.Threading.Task
ve her görevi başlatmak.
Bir .Abort()
iş parçacığı öldürmek için yaptığımda , görevler iptal edilmez.
.Abort()
Görevlerime nasıl iletebilirim ?
Bir iş parçacığında, bazı oluşturmak System.Threading.Task
ve her görevi başlatmak.
Bir .Abort()
iş parçacığı öldürmek için yaptığımda , görevler iptal edilmez.
.Abort()
Görevlerime nasıl iletebilirim ?
Yanıtlar:
Yapamazsın. Görevler, iş parçacığı havuzundan arka plan iş parçacıkları kullanır. Ayrıca İptal yöntemini kullanarak evrelerin iptal edilmesi önerilmez. İptal jetonlarını kullanarak görevleri iptal etmenin uygun bir yolunu açıklayan aşağıdaki blog gönderisine bakabilirsiniz . İşte bir örnek:
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)
dışarıdan (zamana dayalı) bir son tarih vermek için kullanmaktır .
Task
? Gibi bir şey: public int StartNewTask(Action method)
. StartNewTask
Yöntemin içinde yeni bir Task
:: Task task = new Task(() => method()); task.Start();
. Peki nasıl yönetebilirim CancellationToken
? Ayrıca Thread
hala asılı olan bazı Görevler olup olmadığını kontrol etmek için bir mantık uygulamam gerekip gerekmediğini bilmek istiyorum Form.Closing
. İle Threads
kullandığım Thread.Abort()
.
Görevin çalıştığı iş parçacığını yakalarsanız, bir Görevi iptal etmek kolayca mümkündür. İşte bunu göstermek için bir örnek kod:
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();
}
Bunun için en yaygın kullanım durumunu göstermek için Task.Run () yöntemini kullandım.
CancellationToken
desteği olmayan bazı dış kodlar için bir zaman aşımı uygulamak için kullandı ...
CancellationToken
, yarış gerektirmeyen ücretsiz ve hatta daha basit çözümler dikkate alınmalıdır. Yukarıdaki kod, kullanım alanını değil, yalnızca yöntemi göstermektedir.
thread
yerel değişkene geçirileceği anlamına gelir ). Kodunuzda, gerçekten istediğiniz şey olmayan ana iş parçacığını iptal edebilirsiniz. Belki ipliğin iptal edilmeden önce aynı olup olmadığını kontrol etmek, eğer iptal etmekte ısrar ederseniz, iyi bir düşünmek olacaktır
Gibi bu yayını da anlaşılacağı, bu şu şekilde yapılabilir:
int Foo(CancellationToken token)
{
Thread t = Thread.CurrentThread;
using (token.Register(t.Abort))
{
// compute-bound work here
}
}
Çalışmasına rağmen, bu yaklaşımı kullanmanız önerilmez. Görevde çalışan kodu kontrol edebiliyorsanız, iptal işleminin doğru şekilde gerçekleştirilmesi daha iyi olur.
Bu tür şeyler Abort
, kullanımdan kaldırılmanın lojistik nedenlerinden biridir . Her şeyden önce, mümkünse bir konuyu iptal etmek veya durdurmak için kullanmayın Thread.Abort()
. Abort()
yalnızca daha huzurlu taleplere zamanında yanıt vermeyen bir konuyu zorla öldürmek için kullanılmalıdır.
Bununla birlikte, bir iş parçacığının periyodik olarak kontrol edip zarif bir şekilde çıkarken bir iş parçacığının ayarladığı ve beklediği bir paylaşılan iptal göstergesi sağlamanız gerekir. .NET 4, bu amaç için özel olarak tasarlanmış bir yapı içerir CancellationToken
.
Bunu doğrudan yapmaya çalışmamalısınız. Görevlerinizi bir CancellationToken ile çalışacak şekilde tasarlayın ve bu şekilde iptal edin.
Ayrıca, ana iş parçacığınızı bir CancellationToken aracılığıyla işlev görecek şekilde değiştirmenizi tavsiye ederim. Arama Thread.Abort()
kötü bir fikirdir - teşhis edilmesi çok zor olan çeşitli sorunlara yol açabilir. Bunun yerine, bu iş parçacığı görevlerinizin kullandığı İptal işlemini kullanabilir ve aynı CancellationTokenSource
işlem tüm görevlerinizin ve ana iş parçacığınızın iptalini tetiklemek için kullanılabilir .
Bu çok daha basit ve daha güvenli bir tasarıma yol açacaktır.
Prerak K'nin Task.Factory.StartNew () öğesinde anonim bir yöntem kullanmadığınızda CancellationTokens'i kullanma hakkındaki sorusunu yanıtlamak için, CancellationToken'i MSDN örneğinde gösterildiği gibi StartNew () ile başlattığınız yönteme parametre olarak iletirsiniz. burada .
Örneğin
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,
}
Bir görevi iptal etmek için karışık bir yaklaşım kullanıyorum.
Aşağıdaki örneği inceleyin:
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();
}
}
}
Görevler, iptal belirteçleri aracılığıyla iptal için birinci sınıf desteğe sahiptir . İptal belirteçleriyle görevlerinizi oluşturun ve bunları açıkça kullanarak iptal edin.
CancellationToken
Görevin iptal edilip edilmeyeceğini kontrol etmek için a kullanabilirsiniz . Başlamadan önce ("nevermind, bunu zaten yaptım") veya aslında ortadan yarıda kesilmekten mi bahsediyorsun? Eğer eski ise, yardımcı CancellationToken
olabilir; ikincisi, muhtemelen kendi "kefalet" mekanizmanızı uygulamanız ve görev yürütmedeki uygun noktalarda hızlı başarısız olup olmadığınızı kontrol etmeniz gerekecektir (yine de size yardımcı olması için CancellationToken'i kullanabilirsiniz, ancak biraz daha manueldir).
MSDN'nin Görevleri iptal etme hakkında bir makalesi vardır: http://msdn.microsoft.com/en-us/library/dd997396.aspx
Görev ThreadPool'da yürütülüyor (en azından varsayılan fabrika kullanıyorsanız), iş parçacığının iptal edilmesi görevleri etkileyemez. Görevleri iptal etmek için, bkz . Msdn'deki Görev İptal .
Denedim CancellationTokenSource
ama yapamam. Ve bunu kendi yöntemimle yaptım. Ve çalışıyor.
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;
}
}
}
Ve yöntemi çağıran başka bir sınıf:
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();
}
}
}
Görevin kendi iş parçacığında oluşturulmasına Abort
ve Thread
nesnesinin çağrılmasına neden olabilirseniz, iş parçacığı gibi bir görevi iptal edebilirsiniz . Varsayılan olarak, bir görev iş parçacığı havuzu iş parçacığı veya çağıran iş parçacığı üzerinde çalışır - her ikisi de genellikle iptal etmek istediğiniz.
Görevin kendi iş parçacığını almasını sağlamak için, türetilmiş özel bir zamanlayıcı oluşturun TaskScheduler
. Uygulamanızda QueueTask
yeni bir iş parçacığı oluşturun ve bunu görevi yürütmek için kullanın. Daha sonra, görevin hatalı bir durumda bir ile tamamlanmasına neden olacak iş parçacığını iptal edebilirsiniz ThreadAbortException
.
Bu görev zamanlayıcıyı kullanın:
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
}
Görevinize şu şekilde başlayın:
var scheduler = new SingleThreadTaskScheduler();
var task = Task.Factory.StartNew(action, cancellationToken, TaskCreationOptions.LongRunning, scheduler);
Daha sonra, aşağıdakileri iptal edebilirsiniz:
scheduler.TaskThread.Abort();
Bir ipliğin iptal edilmesine ilişkin uyarının hala geçerli olduğuna dikkat edin :
Thread.Abort
Yöntem, dikkatli bir şekilde kullanılmalıdır. Özellikle geçerli iş parçacığı dışında bir iş parçacığını iptal etmek için çağırdığınızda, ThreadAbortException özel durumu atıldığında hangi kodun yürütüldüğünü veya yürütülemediğini bilmiyorsunuz , ayrıca uygulamanızın durumundan veya herhangi bir uygulamanın ve kullanıcı durumundan da emin olamıyorsunuz. korumaktan sorumlu olduğunu. Örneğin, çağrıThread.Abort
statik kurucuların yürütülmesini engelleyebilir veya yönetilmeyen kaynakların serbest bırakılmasını engelleyebilir.
Thread.Abort
, .NET Core'da desteklenmemesidir. Orada kullanmaya çalışmak bir istisnayla sonuçlanır: System.PlatformNotSupportedException: İş parçacığı iptali bu platformda desteklenmiyor. Üçüncü bir uyarı, söz verilen SingleThreadTaskScheduler
görevlerle, yani async
delegelerle oluşturulan görevlerle etkili bir şekilde kullanılamamasıdır . Örneğin, gömülü bir await Task.Delay(1000)
iş parçacığı olmadan çalışır, bu nedenle iş parçacığı olaylarından etkilenmez.