Sdílet prostřednictvím


Timer.Stop Metoda

Definice

Zastaví vyvolání Elapsed události nastavením Enabled na false.

public:
 void Stop();
public void Stop ();
member this.Stop : unit -> unit
Public Sub Stop ()

Příklady

Následující příklad vytvoří instanci objektu System.Timers.Timer , který aktivuje svou Timer.Elapsed událost každé dvě sekundy (2 000 milisekund), nastaví obslužnou rutinu události pro událost a spustí časovač. Obslužná rutina události zobrazí hodnotu ElapsedEventArgs.SignalTime vlastnosti při každém jejím vyvolání. Když uživatel stiskne klávesu Enter, aplikace zavolá metodu Stop před ukončením aplikace.

using System;
using System.Timers;

public class Example
{
   private static System.Timers.Timer aTimer;
   
   public static void Main()
   {
      SetTimer();

      Console.WriteLine("\nPress the Enter key to exit the application...\n");
      Console.WriteLine("The application started at {0:HH:mm:ss.fff}", DateTime.Now);
      Console.ReadLine();
      aTimer.Stop();
      aTimer.Dispose();
      
      Console.WriteLine("Terminating the application...");
   }

   private static void SetTimer()
   {
        // Create a timer with a two second interval.
        aTimer = new System.Timers.Timer(2000);
        // Hook up the Elapsed event for the timer. 
        aTimer.Elapsed += OnTimedEvent;
        aTimer.AutoReset = true;
        aTimer.Enabled = true;
    }

    private static void OnTimedEvent(Object source, ElapsedEventArgs e)
    {
        Console.WriteLine("The Elapsed event was raised at {0:HH:mm:ss.fff}",
                          e.SignalTime);
    }
}
// The example displays output like the following:
//       Press the Enter key to exit the application...
//
//       The application started at 09:40:29.068
//       The Elapsed event was raised at 09:40:31.084
//       The Elapsed event was raised at 09:40:33.100
//       The Elapsed event was raised at 09:40:35.100
//       The Elapsed event was raised at 09:40:37.116
//       The Elapsed event was raised at 09:40:39.116
//       The Elapsed event was raised at 09:40:41.117
//       The Elapsed event was raised at 09:40:43.132
//       The Elapsed event was raised at 09:40:45.133
//       The Elapsed event was raised at 09:40:47.148
//
//       Terminating the application...
open System
open System.Timers

let onTimedEvent source (e: ElapsedEventArgs) =
    printfn $"""The Elapsed event was raised at {e.SignalTime.ToString "HH:mm:ss.fff"}"""

// Create a timer with a two second interval.
let aTimer = new Timer 2000
// Hook up the Elapsed event for the timer. 
aTimer.Elapsed.AddHandler onTimedEvent
aTimer.AutoReset <- true
aTimer.Enabled <- true

printfn "\nPress the Enter key to exit the application...\n"
printfn $"""The application started at {DateTime.Now.ToString "HH:mm:ss.fff"}"""
stdin.ReadLine() |> ignore
aTimer.Stop()
aTimer.Dispose()

printfn "Terminating the application..."

// The example displays output like the following:
//       Press the Enter key to exit the application...
//
//       The application started at 09:40:29.068
//       The Elapsed event was raised at 09:40:31.084
//       The Elapsed event was raised at 09:40:33.100
//       The Elapsed event was raised at 09:40:35.100
//       The Elapsed event was raised at 09:40:37.116
//       The Elapsed event was raised at 09:40:39.116
//       The Elapsed event was raised at 09:40:41.117
//       The Elapsed event was raised at 09:40:43.132
//       The Elapsed event was raised at 09:40:45.133
//       The Elapsed event was raised at 09:40:47.148
//
//       Terminating the application...
Imports System.Timers

Public Module Example
    Private aTimer As System.Timers.Timer

    Public Sub Main()
        SetTimer()

      Console.WriteLine("{0}Press the Enter key to exit the application...{0}",
                        vbCrLf)
      Console.WriteLine("The application started at {0:HH:mm:ss.fff}",
                        DateTime.Now)
      Console.ReadLine()
      aTimer.Stop()
      aTimer.Dispose()

      Console.WriteLine("Terminating the application...")
    End Sub

    Private Sub SetTimer()
        ' Create a timer with a two second interval.
        aTimer = New System.Timers.Timer(2000)
        ' Hook up the Elapsed event for the timer. 
        AddHandler aTimer.Elapsed, AddressOf OnTimedEvent
        aTimer.AutoReset = True
        aTimer.Enabled = True
    End Sub

    ' The event handler for the Timer.Elapsed event. 
    Private Sub OnTimedEvent(source As Object, e As ElapsedEventArgs)
        Console.WriteLine("The Elapsed event was raised at {0:HH:mm:ss.fff}",
                          e.SignalTime)
    End Sub 
End Module
' The example displays output like the following:
'       Press the Enter key to exit the application...
'
'       The application started at 09:40:29.068
'       The Elapsed event was raised at 09:40:31.084
'       The Elapsed event was raised at 09:40:33.100
'       The Elapsed event was raised at 09:40:35.100
'       The Elapsed event was raised at 09:40:37.116
'       The Elapsed event was raised at 09:40:39.116
'       The Elapsed event was raised at 09:40:41.117
'       The Elapsed event was raised at 09:40:43.132
'       The Elapsed event was raised at 09:40:45.133
'       The Elapsed event was raised at 09:40:47.148
'
'       Terminating the application...

Následující příklad kódu ukazuje jeden ze způsobů, jak zabránit vláknu, které volá metodu Stop pokračovat, dokud aktuálně spuštěná Elapsed událost neskončí, a také zabránit dvěma Elapsed událostem v spuštění obslužné rutiny události ve stejnou dobu (často označované jako opakované volání).

Příklad spustí 100 testovacích běhů. Při každém spuštění testu se časovač spustí v intervalu 150 milisekund. Obslužná rutina události používá metodu Thread.Sleep k simulaci úlohy, která se náhodně liší délkou od 50 do 200 milisekund. Testovací metoda také spustí řídicí vlákno, které čeká na sekundu a poté zastaví časovač. Pokud je událost zpracována, když ovládací vlákno zastaví časovač, musí vlákno ovládacího prvku počkat na dokončení události, než bude pokračovat.

Přetížení Interlocked.CompareExchange(Int32, Int32, Int32) metody se používá k tomu, aby se zabránilo opakovanému zaentrování a aby řídicí vlákno pokračovalo, dokud neskončí prováděcí událost. Obslužná rutina události používá metodu CompareExchange(Int32, Int32, Int32) k nastavení řídicí proměnné na hodnotu 1, ale pouze v případě, že hodnota je aktuálně nula. Toto je atomická operace. Pokud je návratová hodnota nula, řídicí proměnná byla nastavena na hodnotu 1 a obslužná rutina události pokračuje. Pokud je návratová hodnota nenulová, událost se jednoduše zahodí, aby se zabránilo opakovanému zavádění. (Pokud by bylo nutné provést každou událost, Monitor byla by lepším způsobem synchronizace událostí třída.) Když obslužná rutina události skončí, nastaví řídicí proměnnou zpět na nulu. Příklad zaznamenává celkový počet událostí, které se spustily, které byly zahozeny z důvodu opakovaného zadání a ke kterým došlo po Stop zavolání metody.

Řídicí vlákno používá metodu CompareExchange(Int32, Int32, Int32) k nastavení řídicí proměnné na -1 (mínus jedna), ale pouze v případě, že hodnota je aktuálně nula. Pokud atomická operace vrátí nenulovou hodnotu, je právě spuštěna událost. Řídicí vlákno počká a pokusí se to znovu. Příklad zaznamenává, kolikrát řídicí vlákno muselo čekat na dokončení události.

using System;
using System.Timers;
using System.Threading;

public class Test
{
    // Change these values to control the behavior of the program.
    private static int testRuns = 100;
    // Times are given in milliseconds:
    private static int testRunsFor = 500;
    private static int timerIntervalBase = 100;
    private static int timerIntervalDelta = 20;

    // Timers.
    private static System.Timers.Timer Timer1 = new System.Timers.Timer();
    private static System.Timers.Timer Timer2 = new System.Timers.Timer();
    private static System.Timers.Timer currentTimer = null;

    private static Random rand = new Random();

    // This is the synchronization point that prevents events
    // from running concurrently, and prevents the main thread
    // from executing code after the Stop method until any
    // event handlers are done executing.
    private static int syncPoint = 0;

    // Count the number of times the event handler is called,
    // is executed, is skipped, or is called after Stop.
    private static int numEvents = 0;
    private static int numExecuted = 0;
    private static int numSkipped = 0;
    private static int numLate = 0;

    // Count the number of times the thread that calls Stop
    // has to wait for an Elapsed event to finish.
    private static int numWaits = 0;

    [MTAThread]
    public static void Main()
    {
        Timer1.Elapsed += new ElapsedEventHandler(Timer1_ElapsedEventHandler);
        Timer2.Elapsed += new ElapsedEventHandler(Timer2_ElapsedEventHandler);

        Console.WriteLine();
        for(int i = 1; i <= testRuns; i++)
        {
            TestRun();
            Console.Write("\rTest {0}/{1}    ", i, testRuns);
        }

        Console.WriteLine("{0} test runs completed.", testRuns);
        Console.WriteLine("{0} events were raised.", numEvents);
        Console.WriteLine("{0} events executed.", numExecuted);
        Console.WriteLine("{0} events were skipped for concurrency.", numSkipped);
        Console.WriteLine("{0} events were skipped because they were late.", numLate);
        Console.WriteLine("Control thread waited {0} times for an event to complete.", numWaits);
    }

    public static void TestRun()
    {
        // Set syncPoint to zero before starting the test
        // run.
        syncPoint = 0;

        // Test runs alternate between Timer1 and Timer2, to avoid
        // race conditions between tests, or with very late events.
        if (currentTimer == Timer1)
            currentTimer = Timer2;
        else
            currentTimer = Timer1;

        currentTimer.Interval = timerIntervalBase
            - timerIntervalDelta + rand.Next(timerIntervalDelta * 2);
        currentTimer.Enabled = true;

        // Start the control thread that shuts off the timer.
        Thread t = new Thread(ControlThreadProc);
        t.Start();

        // Wait until the control thread is done before proceeding.
        // This keeps the test runs from overlapping.
        t.Join();
    }

    private static void ControlThreadProc()
    {
        // Allow the timer to run for a period of time, and then
        // stop it.
        Thread.Sleep(testRunsFor);
        currentTimer.Stop();

        // The 'counted' flag ensures that if this thread has
        // to wait for an event to finish, the wait only gets
        // counted once.
        bool counted = false;

        // Ensure that if an event is currently executing,
        // no further processing is done on this thread until
        // the event handler is finished. This is accomplished
        // by using CompareExchange to place -1 in syncPoint,
        // but only if syncPoint is currently zero (specified
        // by the third parameter of CompareExchange).
        // CompareExchange returns the original value that was
        // in syncPoint. If it was not zero, then there's an
        // event handler running, and it is necessary to try
        // again.
        while (Interlocked.CompareExchange(ref syncPoint, -1, 0) != 0)
        {
            // Give up the rest of this thread's current time
            // slice. This is a naive algorithm for yielding.
            Thread.Sleep(1);

            // Tally a wait, but don't count multiple calls to
            // Thread.Sleep.
            if (!counted)
            {
                numWaits += 1;
                counted = true;
            }
        }

        // Any processing done after this point does not conflict
        // with timer events. This is the purpose of the call to
        // CompareExchange. If the processing done here would not
        // cause a problem when run concurrently with timer events,
        // then there is no need for the extra synchronization.
    }

    // Event-handling methods for the Elapsed events of the two
    // timers.
    //
    private static void Timer1_ElapsedEventHandler(object sender,
        ElapsedEventArgs e)
    {
        HandleElapsed(sender, e);
    }

    private static void Timer2_ElapsedEventHandler(object sender,
        ElapsedEventArgs e)
    {
        HandleElapsed(sender, e);
    }

    private static void HandleElapsed(object sender, ElapsedEventArgs e)
    {
        numEvents += 1;

        // This example assumes that overlapping events can be
        // discarded. That is, if an Elapsed event is raised before
        // the previous event is finished processing, the second
        // event is ignored.
        //
        // CompareExchange is used to take control of syncPoint,
        // and to determine whether the attempt was successful.
        // CompareExchange attempts to put 1 into syncPoint, but
        // only if the current value of syncPoint is zero
        // (specified by the third parameter). If another thread
        // has set syncPoint to 1, or if the control thread has
        // set syncPoint to -1, the current event is skipped.
        // (Normally it would not be necessary to use a local
        // variable for the return value. A local variable is
        // used here to determine the reason the event was
        // skipped.)
        //
        int sync = Interlocked.CompareExchange(ref syncPoint, 1, 0);
        if (sync == 0)
        {
            // No other event was executing.
            // The event handler simulates an amount of work
            // lasting between 50 and 200 milliseconds, so that
            // some events will overlap.
            int delay = timerIntervalBase
                - timerIntervalDelta / 2 + rand.Next(timerIntervalDelta);
            Thread.Sleep(delay);
            numExecuted += 1;

            // Release control of syncPoint.
            syncPoint = 0;
        }
        else
        {
            if (sync == 1) { numSkipped += 1; } else { numLate += 1; }
        }
    }
}

/* On a dual-processor computer, this code example produces
   results similar to the following:

Test 100/100    100 test runs completed.
436 events were raised.
352 events executed.
84 events were skipped for concurrency.
0 events were skipped because they were late.
Control thread waited 77 times for an event to complete.
 */
open System
open System.Threading

// Change these values to control the behavior of the program.
let testRuns = 100
// Times are given in milliseconds:
let testRunsFor = 500
let timerIntervalBase = 100
let timerIntervalDelta = 20

// Timers.
let timer1 = new Timers.Timer()
let timer2 = new Timers.Timer()
let mutable currentTimer = Unchecked.defaultof<Timers.Timer>

let rand = Random()

// This is the synchronization point that prevents events
// from running concurrently, and prevents the main thread
// from executing code after the Stop method until any
// event handlers are done executing.
let mutable syncPoint = 0

// Count the number of times the event handler is called,
// is executed, is skipped, or is called after Stop.
let mutable numEvents = 0
let mutable numExecuted = 0
let mutable numSkipped = 0
let mutable numLate = 0

// Count the number of times the thread that calls Stop
// has to wait for an Elapsed event to finish.
let mutable numWaits = 0

let controlThreadProc () =
    // Allow the timer to run for a period of time, and then
    // stop it.
    Thread.Sleep testRunsFor
    currentTimer.Stop()

    // The 'counted' flag ensures that if this thread has
    // to wait for an event to finish, the wait only gets
    // counted once.
    let mutable counted = false

    // Ensure that if an event is currently executing,
    // no further processing is done on this thread until
    // the event handler is finished. This is accomplished
    // by using CompareExchange to place -1 in syncPoint,
    // but only if syncPoint is currently zero (specified
    // by the third parameter of CompareExchange).
    // CompareExchange returns the original value that was
    // in syncPoint. If it was not zero, then there's an
    // event handler running, and it is necessary to try
    // again.
    while Interlocked.CompareExchange(&syncPoint, -1, 0) <> 0 do
        // Give up the rest of this thread's current time
        // slice. This is a naive algorithm for yielding.
        Thread.Sleep 1

        // Tally a wait, but don't count multiple calls to
        // Thread.Sleep.
        if not counted then
            numWaits <- numWaits + 1
            counted <- true

// Any processing done after this point does not conflict
// with timer events. This is the purpose of the call to
// CompareExchange. If the processing done here would not
// cause a problem when run concurrently with timer events,
// then there is no need for the extra synchronization.

let testRun () =
    // Set syncPoint to zero before starting the test
    // run.
    syncPoint <- 0

    // Test runs alternate between Timer1 and Timer2, to avoid
    // race conditions between tests, or with very late events.
    if currentTimer = timer1 then
        currentTimer <- timer2
    else
        currentTimer <- timer1

    currentTimer.Interval <-
        timerIntervalBase - timerIntervalDelta + (timerIntervalDelta * 2 |> rand.Next)
        |> float

    currentTimer.Enabled <- true

    // Start the control thread that shuts off the timer.
    let t = new Thread(ThreadStart controlThreadProc)
    t.Start()

    // Wait until the control thread is done before proceeding.
    // This keeps the test runs from overlapping.
    t.Join()

let handleElapsed sender e =
    numEvents <- numEvents + 1

    // This example assumes that overlapping events can be
    // discarded. That is, if an Elapsed event is raised before
    // the previous event is finished processing, the second
    // event is ignored.
    //
    // CompareExchange is used to take control of syncPoint,
    // and to determine whether the attempt was successful.
    // CompareExchange attempts to put 1 into syncPoint, but
    // only if the current value of syncPoint is zero
    // (specified by the third parameter). If another thread
    // has set syncPoint to 1, or if the control thread has
    // set syncPoint to -1, the current event is skipped.
    // (Normally it would not be necessary to use a local
    // variable for the return value. A local variable is
    // used here to determine the reason the event was
    // skipped.)
    //
    let sync = Interlocked.CompareExchange(&syncPoint, 1, 0)

    if sync = 0 then
        // No other event was executing.
        // The event handler simulates an amount of work
        // lasting between 50 and 200 milliseconds, so that
        // some events will overlap.
        timerIntervalBase - timerIntervalDelta / 2 + rand.Next timerIntervalDelta
        |> Thread.Sleep

        numExecuted <- numExecuted + 1

        // Release control of syncPoint.
        syncPoint <- 0
    else if sync = 1 then
        numSkipped <- numSkipped + 1
    else
        numLate <- numLate + 1


// Event-handling methods for the Elapsed events of the two
// timers.
let timer1_ElapsedEventHandler = handleElapsed

let timer2_ElapsedEventHandler = handleElapsed

[<EntryPoint; MTAThread>]
let main _ =
    timer1.Elapsed.AddHandler timer1_ElapsedEventHandler
    timer2.Elapsed.AddHandler timer2_ElapsedEventHandler

    printfn ""

    for i = 1 to testRuns do
        testRun ()
        printf $"\rTest {i}/{testRuns}    "

    printfn $"{testRuns} test runs completed."
    printfn $"{numEvents} events were raised."
    printfn $"{numExecuted} events executed."
    printfn $"{numSkipped} events were skipped for concurrency."
    printfn $"{numLate} events were skipped because they were late."
    printfn $"Control thread waited {numWaits} times for an event to complete."
    0

// On a dual-processor computer, this code example produces
// results similar to the following:
//     Test 100/100    100 test runs completed.
//     436 events were raised.
//     352 events executed.
//     84 events were skipped for concurrency.
//     0 events were skipped because they were late.
//     Control thread waited 77 times for an event to complete.
Imports System.Timers
Imports System.Threading

Public Module Test
    
    ' Change these values to control the behavior of the program.
    Private testRuns As Integer = 100 
    ' Times are given in milliseconds:
    Private testRunsFor As Integer = 500
    Private timerIntervalBase As Integer = 100
    Private timerIntervalDelta As Integer = 20

    ' Timers.
    Private WithEvents Timer1 As New System.Timers.Timer
    Private WithEvents Timer2 As New System.Timers.Timer
    Private currentTimer As System.Timers.timer

    Private rand As New Random()

    ' This is the synchronization point that prevents events
    ' from running concurrently, and prevents the main thread 
    ' from executing code after the Stop method until any 
    ' event handlers are done executing.
    Private syncPoint As Integer = 0

    ' Count the number of times the event handler is called,
    ' is executed, is skipped, or is called after Stop.
    Private numEvents As Integer = 0
    Private numExecuted As Integer = 0
    Private numSkipped As Integer = 0
    Private numLate As Integer = 0

    ' Count the number of times the thread that calls Stop
    ' has to wait for an Elapsed event to finish.
    Private numWaits As Integer = 0

    <MTAThread> _
    Sub Main()
        Console.WriteLine()
        For i As Integer = 1 To testRuns
            TestRun
            Console.Write(vbCr & "Test {0}/{1}    ", i, testRuns)
        Next

        Console.WriteLine("{0} test runs completed.", testRuns)
        Console.WriteLine("{0} events were raised.", numEvents)
        Console.WriteLine("{0} events executed.", numExecuted)
        Console.WriteLine("{0} events were skipped for concurrency.", numSkipped)
        Console.WriteLine("{0} events were skipped because they were late.", numLate)
        Console.WriteLine("Control thread waited {0} times for an event to complete.", numWaits)
    End Sub

    Sub TestRun()
        ' Set syncPoint to zero before starting the test 
        ' run. 
        syncPoint = 0

        ' Test runs alternate between Timer1 and Timer2, to avoid
        ' race conditions between tests, or with very late events.
        If currentTimer Is Timer1 Then
            currentTimer = Timer2
        Else
            currentTimer = Timer1
        End If

        currentTimer.Interval = timerIntervalBase _
            - timerIntervalDelta + rand.Next(timerIntervalDelta * 2)
        currentTimer.Enabled = True

        ' Start the control thread that shuts off the timer.
        Dim t As New Thread(AddressOf ControlThreadProc)
        t.Start()

        ' Wait until the control thread is done before proceeding.
        ' This keeps the test runs from overlapping.
        t.Join()

    End Sub


    Private Sub ControlThreadProc()
        ' Allow the timer to run for a period of time, and then 
        ' stop it.
        Thread.Sleep(testRunsFor) 
        currentTimer.Stop

        ' The 'counted' flag ensures that if this thread has
        ' to wait for an event to finish, the wait only gets 
        ' counted once.
        Dim counted As Boolean = False

        ' Ensure that if an event is currently executing,
        ' no further processing is done on this thread until
        ' the event handler is finished. This is accomplished
        ' by using CompareExchange to place -1 in syncPoint,
        ' but only if syncPoint is currently zero (specified
        ' by the third parameter of CompareExchange). 
        ' CompareExchange returns the original value that was
        ' in syncPoint. If it was not zero, then there's an
        ' event handler running, and it is necessary to try
        ' again.
        While Interlocked.CompareExchange(syncPoint, -1, 0) <> 0 
            ' Give up the rest of this thread's current time
            ' slice. This is a naive algorithm for yielding.
            Thread.Sleep(1)

            ' Tally a wait, but don't count multiple calls to
            ' Thread.Sleep.
            If Not counted Then
                numWaits += 1
                counted = True
            End If
        End While

        ' Any processing done after this point does not conflict
        ' with timer events. This is the purpose of the call to
        ' CompareExchange. If the processing done here would not
        ' cause a problem when run concurrently with timer events,
        ' then there is no need for the extra synchronization.
    End Sub


    ' Event-handling methods for the Elapsed events of the two
    ' timers.
    '
    Private Sub Timer1_ElapsedEventHandler(ByVal sender As Object, _
        ByVal e As ElapsedEventArgs) Handles Timer1.Elapsed

        HandleElapsed(sender, e)
    End Sub

    Private Sub Timer2_ElapsedEventHandler(ByVal sender As Object, _
        ByVal e As ElapsedEventArgs) Handles Timer2.Elapsed

        HandleElapsed(sender, e)
    End Sub

    Private Sub HandleElapsed(ByVal sender As Object, ByVal e As ElapsedEventArgs)

        numEvents += 1

        ' This example assumes that overlapping events can be
        ' discarded. That is, if an Elapsed event is raised before 
        ' the previous event is finished processing, the second
        ' event is ignored. 
        '
        ' CompareExchange is used to take control of syncPoint, 
        ' and to determine whether the attempt was successful. 
        ' CompareExchange attempts to put 1 into syncPoint, but
        ' only if the current value of syncPoint is zero 
        ' (specified by the third parameter). If another thread
        ' has set syncPoint to 1, or if the control thread has
        ' set syncPoint to -1, the current event is skipped. 
        ' (Normally it would not be necessary to use a local 
        ' variable for the return value. A local variable is 
        ' used here to determine the reason the event was 
        ' skipped.)
        '
        Dim sync As Integer = Interlocked.CompareExchange(syncPoint, 1, 0)
        If sync = 0 Then
            ' No other event was executing.
            ' The event handler simulates an amount of work
            ' similar to the time between events, so that
            ' some events will overlap.
            Dim delay As Integer = timerIntervalBase _
                - timerIntervalDelta / 2 + rand.Next(timerIntervalDelta)
            Thread.Sleep(delay)
            numExecuted += 1

            ' Release control of syncPoint.
            syncPoint = 0
        Else
            If sync = 1 Then numSkipped += 1 Else numLate += 1
        End If
    End Sub 

End Module

' On a dual-processor computer, this code example produces
' results similar to the following:
'
'Test 100/100    100 test runs completed.
'436 events were raised.
'352 events executed.
'84 events were skipped for concurrency.
'0 events were skipped because they were late.
'Control thread waited 77 times for an event to complete.

Poznámky

Časování můžete také zastavit nastavením Enabled na false.

Poznámka

Signál pro vyvolání Elapsed události je vždy zařazen do fronty ke spuštění ve ThreadPool vlákně, takže metoda zpracování událostí může běžet v jednom vlákně současně s voláním Stop metody v jiném vlákně. To může mít za Elapsed následek vyvolání události po zavolání Stop metody. Druhý příklad kódu v části Příklady ukazuje jeden způsob, jak tuto konflikt časování obejít.

Platí pro

Viz také