كيفية القيام بما يلي: انصات لعدة طلبات الإلغاء
يوضح هذا المثال كيفية انصات إلى إلغاء الأمر اثنين رموز مميزة في نفس الوقت بحيث يمكنك إلغاء الأمر عملية ما إذا كان الرمز المميز أما بطلب.
ملاحظة |
---|
عند "فقط رمز مجلد" هو ممكناً، إلى قطع Studio Vهوual في بعض الحالات تشغيل الخط الذي يطرح استثناء و dهوplay رسالة خطأ تقول "لم يتم التعامل معها من قبل مستخدم رمز استثناء." وهذا خطأ هو benign.اضغط على F5 إلى متابعة منه، ومشاهدة سلوك معالجة الاستثناءات التي يتم هو موضح في الأمثلة أدناه.لمنع الانفصال عن الخطأ أول Visual Studio، فقط إلغاء تحديد "فقط الخاصة بي تعليمات برمجية" خانة الاختيار تحت أدوات، خيارات، تصحيح، عام. |
مثال
في المثال التالي، CreateLinkedTokenSource()أسلوب هو يستخدم لوصل جهازي الرموز المميزة إلى رمز واحد. ويتيح ذلك الرمز المميز لتمريرها إلى وظائف الحصول على رمز مميز كوسيطة الإلغاء واحد فقط. يوضح المثال سيناريو شائع الذي يجب أن يراعيها أسلوب كلاهما الرمز مميز الذي تم إدخاله من خارج الفئة، ورمز مميز تم إنشاؤها داخل الفئة.
Class LinkedTokenSourceDemo
Shared Sub Main()
Dim worker As New WorkerWithTimer()
Dim cts As New CancellationTokenSource()
' Task for UI thread, so we can call Task.Wait wait on the main thread.
Task.Factory.StartNew(Sub()
Console.WriteLine("Press 'c' to cancel within 3 seconds after work begins.")
Console.WriteLine("Or let the task time out by doing nothing.")
If Console.ReadKey().KeyChar = "c"c Then
cts.Cancel()
End If
End Sub
)
' Let the user read the UI message.
Thread.Sleep(1000)
' Start the worker task.
Dim t As Task = Task.Factory.StartNew(Sub() worker.DoWork(cts.Token), cts.Token)
Try
t.Wait()
Catch ae As AggregateException
For Each inner In ae.InnerExceptions
Console.WriteLine(inner.Message)
Next
End Try
Console.WriteLine("Press any key to exit.")
Console.ReadKey()
End Sub
End Class
Class WorkerWithTimer
Dim internalTokenSource As CancellationTokenSource
Dim token As CancellationToken
Dim myTimer As Timer
Public Sub WorkerWithTimer()
internalTokenSource = New CancellationTokenSource()
token = internalTokenSource.Token
' A toy cancellation trigger that times out after 3 seconds
' if the user does not press 'c'.
myTimer = New Timer(New TimerCallback(AddressOf CancelAfterTimeout), Nothing, 3000, 3000)
End Sub
Public Sub DoWork(ByVal externalToken As CancellationToken)
' Create a new token that combines the internal and external tokens.
Dim internalToken As CancellationToken = internalTokenSource.Token
Dim linkedCts As CancellationTokenSource =
CancellationTokenSource.CreateLinkedTokenSource(internalToken, externalToken)
Using (linkedCts)
Try
DoWorkInternal(linkedCts.Token)
Catch e As OperationCanceledException
If e.CancellationToken = internalToken Then
Console.WriteLine("Operation timed out.")
ElseIf e.CancellationToken = externalToken Then
Console.WriteLine("Canceled by external token.")
externalToken.ThrowIfCancellationRequested()
End If
End Try
End Using
End Sub
Private Sub DoWorkInternal(ByVal token As CancellationToken)
For i As Integer = 0 To 1000
If token.IsCancellationRequested Then
' We need to dispose the timer if cancellation
' was requested by the external token.
myTimer.Dispose()
' Output for demonstration purposes.
Console.WriteLine("\r\nCancelling per request.")
' Throw the exception.
token.ThrowIfCancellationRequested()
End If
' Simulating work.
Thread.SpinWait(7500000)
Console.Write("working... ")
Next
End Sub
Public Sub CancelAfterTimeout(ByVal state As Object)
Console.WriteLine("\r\nTimer fired.")
internalTokenSource.Cancel()
myTimer.Dispose()
End Sub
End Class
namespace WaitForMultiple
{
using System;
using System.Threading;
using System.Threading.Tasks;
class LinkedTokenSourceDemo
{
static void Main()
{
WorkerWithTimer worker = new WorkerWithTimer();
CancellationTokenSource cts = new CancellationTokenSource();
// Task for UI thread, so we can call Task.Wait wait on the main thread.
Task.Factory.StartNew(() =>
{
Console.WriteLine("Press 'c' to cancel within 3 seconds after work begins.");
Console.WriteLine("Or let the task time out by doing nothing.");
if (Console.ReadKey().KeyChar == 'c')
cts.Cancel();
});
// Let the user read the UI message.
Thread.Sleep(1000);
// Start the worker task.
Task task = Task.Factory.StartNew(() => worker.DoWork(cts.Token), cts.Token);
try
{
task.Wait(cts.Token);
}
catch (OperationCanceledException e)
{
if (e.CancellationToken == cts.Token)
Console.WriteLine("Canceled from UI thread throwing OCE.");
}
catch (AggregateException ae)
{
Console.WriteLine("AggregateException caught: " + ae.InnerException);
foreach (var inner in ae.InnerExceptions)
{
Console.WriteLine(inner.Message + inner.Source);
}
}
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
class WorkerWithTimer
{
CancellationTokenSource internalTokenSource = new CancellationTokenSource();
CancellationToken internalToken;
CancellationToken externalToken;
Timer timer;
public WorkerWithTimer()
{
internalTokenSource = new CancellationTokenSource();
internalToken = internalTokenSource.Token;
// A toy cancellation trigger that times out after 3 seconds
// if the user does not press 'c'.
timer = new Timer(new TimerCallback(CancelAfterTimeout), null, 3000, 3000);
}
public void DoWork(CancellationToken externalToken)
{
// Create a new token that combines the internal and external tokens.
this.internalToken = internalTokenSource.Token;
this.externalToken = externalToken;
using (CancellationTokenSource linkedCts =
CancellationTokenSource.CreateLinkedTokenSource(internalToken, externalToken))
{
try
{
DoWorkInternal(linkedCts.Token);
}
catch (OperationCanceledException)
{
if (internalToken.IsCancellationRequested)
{
Console.WriteLine("Operation timed out.");
}
else if (externalToken.IsCancellationRequested)
{
Console.WriteLine("Cancelling per user request.");
externalToken.ThrowIfCancellationRequested();
}
}
}
}
private void DoWorkInternal(CancellationToken token)
{
for (int i = 0; i < 1000; i++)
{
if (token.IsCancellationRequested)
{
// We need to dispose the timer if cancellation
// was requested by the external token.
timer.Dispose();
// Throw the exception.
token.ThrowIfCancellationRequested();
}
// Simulating work.
Thread.SpinWait(7500000);
Console.Write("working... ");
}
}
public void CancelAfterTimeout(object state)
{
Console.WriteLine("\r\nTimer fired.");
internalTokenSource.Cancel();
timer.Dispose();
}
}
}
عندما يطرح رمز مرتبط OperationCanceledException، الرمز المميز الذي تم تمريره إلى استثناء هو رمز مرتبط، وأما للمهمة السابقة غير رموز مميزة. إلى تحديد أي من إلى kens تم إلغاء، تحقق من حالة سابقة إلى kens مباشرة.
في ترتيب هو سبيل المثال، AggregateExceptionيجب أن لا يتم طرح، إلا أنه هو حظر هنا لأن في سيناريوهات واقعية أية استثناءات غير ذلك بالإضافة إلى OperationCanceledExceptionالتي يتم طرح من المفوض المهمة يتم التفاف في OperationCanceledException.