كيفية القيام بما يلي: انصات لإلغاء الطلبات التي مقابض انتظار
إذا تم حظر أسلوب بينما هو ينتظر حدث إلى أن إليه صوت، فإنه لا يمكن أن يتحقق القيمة الرمز المميز للإلغاء و استجابة في الوقت المناسب. يظهر المثال أول كيفية إلى إلى حل هذه المشكلة عند العمل مع أحداث مثل System.Threading.ManualResetEventالتي قم بشكل أصلي لا تعتمد إطار عمل موحد للإلغاء. يظهر المثال الثاني أسلوباً أكثر تنظيماً ويستخدم System.Threading.ManualResetEventSlim، مما أدى دعم الموحد الإلغاء.
ملاحظة |
---|
عند "فقط رمز مجلد" هو ممكناً، إلى قطع Studio Vهوual في بعض الحالات تشغيل الخط الذي يطرح استثناء و dهوplay رسالة خطأ تقول "لم يتم التعامل معها من قبل مستخدم رمز استثناء." وهذا خطأ هو benign.اضغط على F5 إلى متابعة منه، ومشاهدة سلوك معالجة الاستثناءات التي يتم هو موضح في الأمثلة أدناه.لمنع الانفصال عن الخطأ أول Visual Studio، فقط إلغاء تحديد "فقط الخاصة بي تعليمات برمجية" خانة الاختيار تحت أدوات، خيارات، تصحيح، عام. |
مثال
يستخدم المثال التالي ManualResetEventإلى شرح كيفية إلى إلغاء حظر مقابض انتظار لا تعتمد الإلغاء موحدة.
' Imports System
' Imports System.Threading
' Imports System.Threading.Tasks
Class CancelOldStyleEvents
' Old-style MRE that doesn't support unified cancellation.
Shared mre As New ManualResetEvent(False)
Shared Sub Main()
Dim cts As New CancellationTokenSource()
' Pass the same token source to the delegate and to the task instance.
Task.Factory.StartNew(Sub() DoWork(cts.Token), cts.Token)
Console.WriteLine("Press c to cancel, p to pause, or s to start/restart.")
Console.WriteLine("Or any other key to exit.")
' Old-style UI thread.
Dim goAgain As Boolean = True
While goAgain = True
Dim ch As Char = Console.ReadKey().KeyChar
Select Case ch
Case "c"c
cts.Cancel()
Case "p"c
mre.Reset()
Case "s"c
mre.Set()
Case Else
goAgain = False
End Select
Thread.Sleep(100)
End While
End Sub
Shared Sub DoWork(ByVal token As CancellationToken)
While True
' Wait on the event if it is not signaled.
Dim myWaitHandle(2) As WaitHandle
myWaitHandle(0) = mre
myWaitHandle(1) = token.WaitHandle
Dim eventThatSignaledIndex =
WaitHandle.WaitAny(myWaitHandle, _
New TimeSpan(0, 0, 20))
' Were we canceled while waiting?
' The first If statement is equivalent to
' token.ThrowIfCancellationRequested()
If eventThatSignaledIndex = 1 Then
Console.WriteLine("The wait operation was canceled.")
Throw New OperationCanceledException(token)
' Were we canceled while running?
ElseIf token.IsCancellationRequested = True Then
Console.WriteLine("Cancelling per user request.")
token.ThrowIfCancellationRequested()
' Did we time out?
ElseIf eventThatSignaledIndex = WaitHandle.WaitTimeout Then
Console.WriteLine("The wait operation timed out.")
Exit While
Else
' Simulating work.
Console.Write("Working... ")
Thread.SpinWait(5000000)
End If
End While
End Sub
End Class
using System;
using System.Threading;
using System.Threading.Tasks;
class CancelOldStyleEvents
{
// Old-style MRE that doesn't support unified cancellation.
static ManualResetEvent mre = new ManualResetEvent(false);
static void Main()
{
var cts = new CancellationTokenSource();
// Pass the same token source to the delegate and to the task instance.
Task.Factory.StartNew(() => DoWork(cts.Token), cts.Token);
Console.WriteLine("Press s to start/restart, p to pause, or c to cancel.");
Console.WriteLine("Or any other key to exit.");
// Old-style UI thread.
bool goAgain = true;
while (goAgain)
{
char ch = Console.ReadKey().KeyChar;
switch (ch)
{
case 'c':
cts.Cancel();
break;
case 'p':
mre.Reset();
break;
case 's':
mre.Set();
break;
default:
goAgain = false;
break;
}
Thread.Sleep(100);
}
}
static void DoWork(CancellationToken token)
{
while (true)
{
// Wait on the event if it is not signaled.
int eventThatSignaledIndex =
WaitHandle.WaitAny(new WaitHandle[] { mre, token.WaitHandle },
new TimeSpan(0, 0, 20));
// Were we canceled while waiting?
if (eventThatSignaledIndex == 1)
{
Console.WriteLine("The wait operation was canceled.");
throw new OperationCanceledException(token);
}
// Were we canceled while running?
else if (token.IsCancellationRequested)
{
Console.WriteLine("I was canceled while running.");
token.ThrowIfCancellationRequested();
}
// Did we time out?
else if (eventThatSignaledIndex == WaitHandle.WaitTimeout)
{
Console.WriteLine("I timed out.");
break;
}
else
{
Console.Write("Working... ");
// Simulating work.
Thread.SpinWait(5000000);
}
}
}
}
يستخدم المثال التالي ManualResetEventSlimإلى شرح كيفية إلى إلغاء حظر الأوليات التنسيق الذي يدعم الإصداران الإلغاء موحدة. يمكن استخدام الطريقة نفسها مع الأوليات الخفيف التنسيق الأخرى، مثل كـ SemaphoreSlimو CountdownEvent.
Class CancelNewStyleEvents
' New-style MRESlim that supports unified cancellation
' in its Wait methods.
Shared mres As ManualResetEventSlim = New ManualResetEventSlim(False)
Shared Sub Main()
Dim cts As New CancellationTokenSource()
' Pass the same token source to the delegate and to the task instance.
Task.Factory.StartNew(Sub() DoWork(cts.Token), cts.Token)
Console.WriteLine("Press c to cancel, p to pause, or s to start/restart,")
Console.WriteLine("or any other key to exit.")
' New-style UI thread.
Dim goAgain As Boolean = True
While goAgain = True
Dim ch As Char = Console.ReadKey().KeyChar
Select Case ch
Case "c"c
' Token can only be canceled once.
cts.Cancel()
Case "p"c
mres.Reset()
Case "s"c
mres.Set()
Case Else
goAgain = False
End Select
Thread.Sleep(100)
End While
End Sub
Shared Sub DoWork(ByVal token As CancellationToken)
While True
If token.IsCancellationRequested Then
Console.WriteLine("Canceled while running.")
token.ThrowIfCancellationRequested()
End If
' Wait on the event to be signaled
' or the token to be canceled,
' whichever comes first. The token
' will throw an exception if it is canceled
' while the thread is waiting on the event.
Try
' mres is a ManualResetEventSlim
mres.Wait(token)
Catch e As OperationCanceledException
' Throw immediately to be responsive. The
' alternative is to do one more item of work,
' and throw on next iteration, because
' IsCancellationRequested will be true.
Console.WriteLine("Canceled while waiting.")
Throw
End Try
' Simulating work.
Console.Write("Working...")
Thread.SpinWait(500000)
End While
End Sub
End Class
class CancelNewStyleEvents
{
// New-style MRESlim that supports unified cancellation
// in its Wait methods.
static ManualResetEventSlim mres = new ManualResetEventSlim(false);
static void Main()
{
var cts = new CancellationTokenSource();
// Pass the same token source to the delegate and to the task instance.
Task.Factory.StartNew(() => DoWork(cts.Token), cts.Token);
Console.WriteLine("Press c to cancel, p to pause, or s to start/restart,");
Console.WriteLine("or any other key to exit.");
// New-style UI thread.
bool goAgain = true;
while (goAgain)
{
char ch = Console.ReadKey().KeyChar;
switch (ch)
{
case 'c':
// Token can only be canceled once.
cts.Cancel();
break;
case 'p':
mres.Reset();
break;
case 's':
mres.Set();
break;
default:
goAgain = false;
break;
}
Thread.Sleep(100);
}
}
static void DoWork(CancellationToken token)
{
while (true)
{
if (token.IsCancellationRequested)
{
Console.WriteLine("Canceled while running.");
token.ThrowIfCancellationRequested();
}
// Wait on the event to be signaled
// or the token to be canceled,
// whichever comes first. The token
// will throw an exception if it is canceled
// while the thread is waiting on the event.
try
{
// mres is a ManualResetEventSlim
mres.Wait(token);
}
catch (OperationCanceledException)
{
// Throw immediately to be responsive. The
// alternative is to do one more item of work,
// and throw on next iteration, because
// IsCancellationRequested will be true.
Console.WriteLine("The wait operation was canceled.");
throw;
}
Console.Write("Working...");
// Simulating work.
Thread.SpinWait(500000);
}
}
}