مشاركة عبر


الإلغاء

.NET Framework الإصدار 4يقدم نموذج موحد جديد للإلغاء تعاونية لتشغيلها لفترة طويلة غير متزامن أو غير متزامن العمليات. Th هو طراز هو استناداً إلى كائن خفيفة تسمى رمز مميز لإلغاء. الكائن يستدعي عملية cancelable، على سبيل المثال بإنشاء مؤشر ترابط جديد أو مهمة، قم بتمرير إلى ken إلى العملية. يمكن بدوره الوصول لعملية نسخ إلى ken إلى العمليات غير ذلك. في بعض وقت لاحق، الكائن الذي يقوم بإنشاء الرمز المميز يمكنك استخدامها لطلب أن إيقاف تشغيل التي عليها هو القيام. يمكن طلب كائن فقط هو sue طلب الإلغاء، و lهوtener كل هو مسؤولة عن noticing الطلب والرد عليها في الوقت المناسب. يظهر التوضيح التالي العلاقة بين رمز مميز المصدر وكافة النسخ من الرمز المميز الخاص به.

CancellationTokenSource وCancellationTokens

طراز الإلغاء جديد يسهل إلى إنشاء التطبيقات التي تتعرف على الإلغاء والمكتبات، ويدعم الميزات التالية:

  • تم الإلغاء تعاونية و هو غير مفروضة تشغيل وحدة الإصغاء. يحدد وحدة الإصغاء كيف إلى أمان ينهي استجابة إلى طلب إلغاء.

  • طلب هو dهوtinct من lهوtening. كائن يستدعي عملية cancelable يمكن التحكم متى (إذا سبق) الإلغاء هو المطلوبة.

  • الكائن الذي يطلب يصدر طلب الإلغاء إلى الجميع نسخ ken إلى باستخدام استدعاء أسلوب واحد فقط.

  • يمكن انصات موزع رسائل إلى رموز متعددة في نفس الوقت بواسطة ضمها إلى رمز مرتبط واحد .

  • قد تلاحظ رمز مستخدم و الاستجابة إلى طلبات الإلغاء من تعليمات برمجية للمكتبة، و يمكن أن تلاحظ رمز مكتبة و الاستجابة لطلبات الإلغاء من تعليمات برمجية للمستخدم.

  • يمكن أن يتم إعلامك رسائل طلبات الإلغاء بواسطة الاستقصاء تسجيل رد اتصال أو انتظار مقابض الانتظار.

أنواع جديد الإلغاء

إطار جديد لإلغاء هو كمجموعة من أنواع ذات الصلة، وهي عبارة عن lهوted في الجدول التالي.

نوع اسم

الوصف

CancellationTokenSource

الكائن الذي يقوم بإنشاء رمز مميز لإلغاء و أيضا المشكلات المتعلقة بطلب الإلغاء الجميع النسخ هذا الرمز المميز.

CancellationToken

اكتب قيمة خفيفة pكـsed لرسائل أو أكثر، عادة كـ معلمة أسلوب. مراقبة رسائل القيمة IsCancellationRequestedخاصية الرمز المميز بالتحقق من اتصال أو رد الاتصال، أو مؤشر الانتظار.

OperationCanceledException

جديد قبول التحميلات الزائدة هذا ‏‏ استثناء CancellationToken كمعلمة إدخال. يمكنك بشكل اختياري لرسائل طرح هذا ‏‏ استثناء للتحقق من مصدر للإلغاء وإعلام الآخرين التي تم إرسال استجابة إلى طلب إلغاء.

تم دمج الطراز الجديد الإلغاء في .NET Frameworkأنواع عديدة. تلك التي الأكثر أهمية System.Threading.Tasks.Parallel، System.Threading.Tasks.Task، و System.Linq.ParallelEnumerable. We recommend that you استخدم this جديد cancellation model for الجميع جديد مكتبة و تطبيق تعليمات برمجية.

مثال على رمز برمجي

في the following مثال, the requesting كائن creates a CancellationTokenSource كائن, و then passes its Token خاصية إلى the cancelable تشغيل. The تشغيل that receives the طلب monitors the القيمة of the IsCancellationRequested خاصية of the token بواسطة polling. When the القيمة becomes true, the listener can ينهي في whatever manner هو appropriate. في this مثال, the أسلوب just exits, which هو الجميع that هو مطلوب في many cases.

ملاحظةملاحظة

The مثال uses the QueueUserWorkItem أسلوب إلى demonstrate that the جديد cancellation framework هو متوافق مع قديم APIs. For an مثال that uses the جديد, preferred System.Threading.Tasks.Task نوع, see كيفية: إلغاء مهمة.

Shared Sub CancelWithThreadPoolMiniSnippet()


    'Thread 1: The Requestor
    ' Create the token source.
    Dim cts As New CancellationTokenSource()

    ' Pass the token to the cancelable operation.
    ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf DoSomeWork), cts.Token)

    ' Request cancellation by setting a flag on the token.
    cts.Cancel()
    ' end block
End Sub

'Thread 2: The Listener
Shared Sub DoSomeWork(ByVal obj As Object)

    Dim token As CancellationToken = CType(obj, CancellationToken)
    For i As Integer = 0 To 1000000

        ' Simulating work.
        Thread.SpinWait(5000000)

        If token.IsCancellationRequested Then

            ' Perform cleanup if necessary.
            '...
            ' Terminate the operation.
            Exit For
        End If
    Next
End Sub
static void CancelWithThreadPoolMiniSnippet()
{

    //Thread 1: The Requestor
    // Create the token source.
    CancellationTokenSource cts = new CancellationTokenSource();

    // Pass the token to the cancelable operation.
    ThreadPool.QueueUserWorkItem(new WaitCallback(DoSomeWork), cts.Token);

    // Request cancellation by setting a flag on the token.
    cts.Cancel();
}

//Thread 2: The Listener
static void DoSomeWork(object obj)
{
    CancellationToken token = (CancellationToken)obj;
    for (int i = 0; i < 100000; i++)
    {
        // Simulating work.
        Thread.SpinWait(5000000);

        if (token.IsCancellationRequested)
        {
            // Perform cleanup if necessary.
            //...
            // Terminate the operation.
            break;
        }
    }
}

تشغيل Cancellation Versus كائن Cancellation

في جديد إطار عمل للإلغاء، إلغاء تشير إلى العمليات، لا على الكائنات. طلب الإلغاء يعني أنه يجب إيقاف تشغيل أسرع وقت ممكن بعد أي التنظيف المطلوبة هو تنفيذه. يجب أن يشير رمز الإلغاء واحد إلى واحد "cancelable تشغيل،" ولكن قد يتم تنفيذ هذه تشغيل في جهاز برنامج. بعد IsCancellationRequestedتم تعيين خاصية من الرمز المميز true، فإنه لا يمكن إعادة تعيينها إلى false. ولذلك، إلغاء رموز مميزة لا يمكن استخدامها بعد أن تم إلغاؤها.

إذا كنت بحاجة إليه إلغاء كائن، يمكنك bكـe على تقنية إلغاء تشغيل، فإنه كـ هو موضح في المثال التالي.

Dim cts As New CancellationTokenSource()
Dim token As CancellationToken = cts.Token

' User defined Class with its own method for cancellation
Dim obj1 As New MyCancelableObject()
Dim obj2 As New MyCancelableObject()
Dim obj3 As New MyCancelableObject()

' Register the object's cancel method with the token's
' cancellation request.
token.Register(Sub() obj1.Cancel())
token.Register(Sub() obj2.Cancel())
token.Register(Sub() obj3.Cancel())

' Request cancellation on the token.
cts.Cancel()
CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken token = cts.Token;

// User defined Class with its own method for cancellation
var obj1 = new MyCancelableObject();
var obj2 = new MyCancelableObject();
var obj3 = new MyCancelableObject();

// Register the object's cancel method with the token's
// cancellation request.
token.Register(() => obj1.Cancel());
token.Register(() => obj2.Cancel());
token.Register(() => obj3.Cancel());

// Request cancellation on the token.
cts.Cancel();

إذا كان كائن يعتمد المزيد عملية cancelable المتزامنة، تمرير ken إلى منفصلة كإدخال إلى كل عملية cancelable مميزة. بهذه الطريقة، واحد يمكن أن يتم إلغاء العملية دون التأثير على الآخرين.

الاستماع ويستجيب لطلبات إلغاء إلى

يحدد implementer لعملية cancelable، بتفويض مستخدم، كيف إلى ينهي تشغيل استجابة إلى طلب إلغاء. في كثير من الحالات، مستخدم المفوض يمكن فقط تنفيذ أي مطلوب تنظيف ثم إعادة فورا.

ومع ذلك، في حالات أكثر تعقيداً، قد يكون ضروريا للمفوض مستخدم لإعلام المكتبة تعليمات برمجية حدث الإلغاء. في مثل هذه الحالات، بالطريقة الصحيحة لإنهاء تشغيل هو لمفوض استدعاء ThrowIfCancellationRequested، مما يؤدي OperationCanceledExceptionأن يتم طرح. التحميلات الزائدة جديدة من هذا ‏‏ استثناء في .NET Framework الإصدار 4الحصول CancellationTokenكـ على وسيطة. رمز مكتبة يمكن تصفية هذا ‏‏ استثناء تشغيل مؤشر ترابط المفوض مستخدم، و فحص رمز مميز للاستثناء لتحديد ما إذا كان ‏‏ استثناء إلى إلغاء التعاونية، أو الاستثنائية من الموقف.

Taskمقابض فئة "OperationCanceledExceptionفي هذه الطريقة." لمزيد من المعلومات، راجع Task Cancellation.

بواسطة استقصاء

لحسابات تشغيلها لفترة طويلة هذه الحلقة أو recurse، يمكنك انصات لرسالة بإلغاء طلب بالتحقق دورياً للقيمة CancellationToken.IsCancellationRequestedخاصية. إذا كانت القيمة هو true، ثم يجب أن الأسلوب تنظيف وإنهاء كأسرع ما يمكن. تكرار الاستقصاء الأمثل يعتمد تشغيل نوع تطبيق. هو إلى المطور لتحديد تكرار الاستقصاء أفضل لأي برنامج معين. الاستقصاء نفسه غير ملحوظ يؤثر على الأداء. يوضح المثال التالي طريقة واحدة ممكنة إلى الاستقصاء.

    Shared Sub NestedLoops(ByVal rect As Rectangle, ByVal token As CancellationToken)

        For x As Integer = 0 To rect.columns

            For y As Integer = 0 To rect.rows

                ' Simulating work.
                Thread.SpinWait(5000)
                Console.Write("0' end block,1' end block ", x, y)
            Next

            ' Assume that we know that the inner loop is very fast.
            ' Therefore, checking once per row is sufficient.
            If token.IsCancellationRequested = True Then

                ' Cleanup or undo here if necessary...
                Console.WriteLine("\r\nCancelling after row 0' end block.", x)
                Console.WriteLine("Press any key to exit.")
                ' then...
                Exit For
                ' ...or, if using Task:
                ' token.ThrowIfCancellationRequested()
            End If
        Next
    End Sub

static void NestedLoops(Rectangle rect, CancellationToken token)
{
    for (int x = 0; x < rect.columns && !token.IsCancellationRequested; x++)
    {
        for (int y = 0; y < rect.rows; y++)
        {
            // Simulating work.
            Thread.SpinWait(5000);
            Console.Write("{0},{1} ", x, y);
        }

        // Assume that we know that the inner loop is very fast.
        // Therefore, checking once per row is sufficient.
        if (token.IsCancellationRequested)
        {
            // Cleanup or undo here if necessary...
            Console.WriteLine("\r\nCancelling after row {0}.", x);
            Console.WriteLine("Press any key to exit.");
            // then...
            break;
            // ...or, if using Task:
            // token.ThrowIfCancellationRequested();
        }
    }
}

لمثال كامل أكثر ، راجع كيفية القيام بما يلي: انصات لطلبات الإلغاء بواسطة استقصاء.

بواسطة تسجيل رد اتصال

يمكن أن تصبح حظر بعض العمليات بطريقة التي لا يمكن بتفحص القيمة الرمز المميز للإلغاء في الوقت المناسب. يمكن لهذه الحالات، regهوter أسلوب استدعاء الأسلوب عند طلب الإلغاء unblocks هو التي تم تلقيها.

CancellationTokenRegister()إرجاع الأسلوب CancellationTokenRegistrationالكائن الذي هو المستخدم خصيصا لترتيب هو الغرض. يوضح المثال التالي كيفية إلى استخدام Register()أسلوب إلى إلغاء عنصر غير متزامن ويب طلب.

Dim cts As New CancellationTokenSource()
Dim token As CancellationToken = cts.Token
Dim wc As New WebClient()

' To request cancellation on the token
' will call CancelAsync on the WebClient.
token.Register(Sub() wc.CancelAsync())

Console.WriteLine("Starting request")
wc.DownloadStringAsync(New Uri("https://www.contoso.com"))
CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken token = cts.Token;            
WebClient wc = new WebClient();

// To request cancellation on the token
// will call CancelAsync on the WebClient.
token.Register(() => wc.CancelAsync());

Console.WriteLine("Starting request");
wc.DownloadStringAsync(new Uri("https://www.contoso.com"));

CancellationTokenRegistrationكائن إدارة المزامنة مؤشر ترابط و يؤكد أن رد الاتصال سيتوقف التنفيذ عند يؤشر دقيقة في الوقت.

في ترتيب إلى ضمان استجابة النظام و إلى تجنب deadlocks، يجب اتباع الإرشادات التالية عند تسجيل رد الاتصال:

  • يجب أن يكون الأسلوب رد الاتصال بسرعة لأن ذلك هو تسمى شكل متزامن ولذلك استدعاء Cancelلا يرجع إلى أن تقوم بإرجاع رد الاتصال.

  • إذا قمت باستدعاء Disposeأثناء رد الاتصال هو قيد التشغيل، وتم الاحتفاظ بتأمين الذي رد الاتصال هو انتظار، يمكن البرنامج حالة توقف تام. بعد Disposeإرجاع، يمكنك تحرير أي من موارد المطلوبة من قبل رد الاتصال.

  • عمليات الاستدعاء يجب عدم إجراء أي يدوي مؤشر ترابط أو SynchronizationContextالاستخدام في رد الاتصال. إذا كان يجب تشغيل رد اتصال على مؤشر ترابط معينة، استخدم System.Threading.CancellationTokenRegistrationالدالة الإنشائية إمكانية تحديد التي syncContext هدف هو النشطة SynchronizationContext.Current. يمكن أن يؤدي تنفيذ الترابط اليدوية في رد اتصال في حالة توقف تام.

لمثال كامل أكثر ، راجع كيفية القيام بما يلي: قم بتسجيل عمليات الاسترجاعات لطلبات الإلغاء.

بواسطة استخدام مؤشر الانتظار

متى يمكن منع عملية cancelable أثناء انتظار تشغيل مزامنة مجموعة أساسية مثل تشغيل System.Threading.ManualResetEventأو System.Threading.Semaphore، يمكنك استخدام CancellationToken.WaitHandleخاصية إلى تمكين العملية إلى الانتظار تشغيل حدث وطلب الإلغاء. سوف تصبح إليه صوت مؤشر الانتظار الإلغاء إلى ken استجابة إلى طلب إلغاء، والأسلوب استخدام القيمة الإرجاع ل WaitAnyالأسلوب إلى لتحديد ما إذا كان الإلغاء إلى ken الذي إليه صوت. تشغيل يمكن ثم فقط إنهاء أو رمى OperationCanceledException، الشكل المناسب.

' 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))
// Wait on the event if it is not signaled.
int eventThatSignaledIndex =
    WaitHandle.WaitAny(new WaitHandle[] { mre, token.WaitHandle },
                        new TimeSpan(0, 0, 20));

في تعليمات برمجية الجديدة التي تستهدف في .NET Framework الإصدار 4، System.Threading.ManualResetEventSlimو System.Threading.SemaphoreSlimكليهما يدعم إطار عمل الإلغاء الجديد في الخاصة بهم Waitالأساليب. يمكنك تمرير CancellationTokenالأسلوب، وعندما يتم طلب الإلغاء، ينشط حدث ويطرح على OperationCanceledException.

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)
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);

لمثال كامل أكثر ، راجع كيفية القيام بما يلي: انصات لإلغاء الطلبات التي مقابض انتظار.

الاستماع إلى الرموز المميزة متعددة في نفس الوقت

في بعض الحالات، قد يكون موزع رسائل للاستماع إلى إلغاء عدة رموز مميزة في نفس الوقت. على سبيل المثال، قد يكون عملية cancelable لمراقبة رمز إلغاء داخلية بالإضافة إلى pكـsed الرمز مميز في الخارج كـ وسيطة إلى معلمة أسلوب. للقيام بذلك، قم بإنشاء مصدر الرمز مميز مرتبطة الانضمام إلى الرموز المميزة أو أكثر إلى رمز واحد، كـ هو موضح في المثال التالي.

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
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();
            }
        }
    }
}

لاحظ أنه يجب أن يتصل Disposeتشغيل مصدر الرموز المميزة المرتبطة عندما تنهي عملك مع it. لمثال كامل أكثر ، راجع كيفية القيام بما يلي: انصات لعدة طلبات الإلغاء.

التعاون بين مكتبة رمز و تعليمات برمجية الخاصة بمستخدم

إطار عمل موحد إلغاء الأمر lation يجعل من الممكن لمكتبة برمجية إلغاء الأمر التعليمة البرمجية للمستخدم، والتعليمات البرمجية للمستخدم إلى إلغاء الأمر تعليمات برمجية المكتبة بطريقة تعاونية. يعتمد التعاون متجانسة تشغيل كل جانب باتباع الإرشادات التالية:

  • في حالة توفير رمز مكتبة العمليات cancelable، يجب أيضا توفير الأساليب العامة التي تقبل رمز إلغاء خارجية حيث تعليمات برمجية الخاصة بالمستخدم يمكن طلب الإلغاء.

  • إذا استدعت تعليمات برمجية للمكتبة في رمز مستخدم، التعليمة البرمجية مكتبة يجب تفسير OperationCanceledException(externalToken) كـ الإلغاء تعاونية ، وليس بالضرورة كـ استثناء فشل.

  • يجب أن يحاول مستخدم-المفوضون الاستجابة إلى طلبات الإلغاء من تعليمات برمجية للمكتبة في الوقت المناسب.

System.Threading.Tasks.TaskوSystem.Linq.ParallelEnumerableأمثلة على الفئات التي تلي هذه الإرشادات. للمزيد من المعلومات، راجع Cancellation (Task Parallel Library) وكيفية: إلغاء استعلام PLINQ.

راجع أيضًا:

موارد أخرى

مدارة مؤشر الترابط التشعبي أساسيات