Czasomierze
Platforma .NET udostępnia trzy czasomierze do użycia w środowisku wielowątkowym:
- System.Threading.Timer, który wykonuje pojedynczą metodę wywołania zwrotnego w wątku ThreadPool w regularnych odstępach czasu.
- System.Timers.Timer, który domyślnie zgłasza zdarzenie w wątku ThreadPool w regularnych odstępach czasu.
- System.Threading.PeriodicTimer, dzięki czemu obiekt wywołujący może wykonać pracę po oczekiwaniu na poszczególne znaczniki czasomierza.
Uwaga
Niektóre implementacje platformy .NET mogą obejmować dodatkowe czasomierze:
- System.Windows.Forms.Timer: składnik Windows Forms, który uruchamia zdarzenie w regularnych odstępach czasu. Składnik nie ma interfejsu użytkownika i jest przeznaczony do użytku w środowisku jednowątkowym.
- System.Web.UI.Timer: składnik ASP.NET, który wykonuje asynchroniczne lub synchroniczne ogłaszanie zwrotne stron internetowych w regularnych odstępach czasu.
- System.Windows.Threading.DispatcherTimer: czasomierz zintegrowany z kolejką Dispatcher , który jest przetwarzany w określonym przedziale czasu i o określonym priorytetzie.
Klasa System.Threading.Timer
Klasa System.Threading.Timer umożliwia ciągłe wywoływanie delegata w określonych interwałach czasu. Tej klasy można również użyć do zaplanowania pojedynczego wywołania delegata w określonym przedziale czasu. Delegat jest wykonywany w wątku ThreadPool .
Podczas tworzenia System.Threading.Timer obiektu należy określić TimerCallback delegata definiującego metodę wywołania zwrotnego, opcjonalny obiekt stanu przekazywany do wywołania zwrotnego, czas opóźnienia przed pierwszym wywołaniem wywołania zwrotnego oraz interwał czasu między wywołaniami wywołania zwrotnego wywołań. Aby anulować oczekujący czasomierz, wywołaj metodę Timer.Dispose .
Poniższy przykład tworzy czasomierz, który wywołuje dostarczonego delegata po raz pierwszy po jednej sekundzie (1000 milisekund), a następnie wywołuje go co dwie sekundy. Obiekt stanu w przykładzie służy do liczenia liczby wywołań delegata. Czasomierz jest zatrzymywany, gdy delegat został wywołany co najmniej 10 razy.
using namespace System;
using namespace System::Threading;
ref class TimerState
{
public:
int counter;
};
ref class Example
{
private:
static Timer^ timer;
public:
static void TimerTask(Object^ state)
{
Console::WriteLine("{0:HH:mm:ss.fff}: starting a new callback.", DateTime::Now);
TimerState^ timerState = dynamic_cast<TimerState^>(state);
Interlocked::Increment(timerState->counter);
}
static void Main()
{
TimerCallback^ tcb = gcnew TimerCallback(&TimerTask);
TimerState^ state = gcnew TimerState();
state->counter = 0;
timer = gcnew Timer(tcb, state, 1000, 2000);
while (state->counter <= 10)
{
Thread::Sleep(1000);
}
timer->~Timer();
Console::WriteLine("{0:HH:mm:ss.fff}: done.", DateTime::Now);
}
};
int main()
{
Example::Main();
}
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
private static Timer timer;
static void Main(string[] args)
{
var timerState = new TimerState { Counter = 0 };
timer = new Timer(
callback: new TimerCallback(TimerTask),
state: timerState,
dueTime: 1000,
period: 2000);
while (timerState.Counter <= 10)
{
Task.Delay(1000).Wait();
}
timer.Dispose();
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff}: done.");
}
private static void TimerTask(object timerState)
{
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff}: starting a new callback.");
var state = timerState as TimerState;
Interlocked.Increment(ref state.Counter);
}
class TimerState
{
public int Counter;
}
}
Imports System.Threading
Module Program
Private Timer As Timer
Sub Main(args As String())
Dim StateObj As New TimerState
StateObj.Counter = 0
Timer = New Timer(New TimerCallback(AddressOf TimerTask), StateObj, 1000, 2000)
While StateObj.Counter <= 10
Task.Delay(1000).Wait()
End While
Timer.Dispose()
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff}: done.")
End Sub
Private Sub TimerTask(ByVal StateObj As Object)
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff}: starting a new callback.")
Dim State As TimerState = CType(StateObj, TimerState)
Interlocked.Increment(State.Counter)
End Sub
Private Class TimerState
Public Counter As Integer
End Class
End Module
Aby uzyskać więcej informacji i przykładów, zobacz System.Threading.Timer.
Klasa System.Timers.Timer
Innym czasomierzem, który może być używany w środowisku wielowątkowym, jest to System.Timers.Timer , że domyślnie zgłasza zdarzenie w wątku ThreadPool .
Podczas tworzenia System.Timers.Timer obiektu można określić interwał czasu, w którym ma zostać Elapsed wyświetlone zdarzenie. Enabled Użyj właściwości , aby wskazać, czy czasomierz powinien zgłosić Elapsed zdarzenie. Jeśli chcesz, Elapsed aby zdarzenie było zgłaszane tylko raz po upływie określonego interwału, ustaw wartość AutoResetfalse
. Wartość AutoReset domyślna właściwości to true
, co oznacza, że Elapsed zdarzenie jest regularnie wywoływane w interwale zdefiniowanym Interval przez właściwość .
Aby uzyskać więcej informacji i przykładów, zobacz System.Timers.Timer.
Klasa System.Threading.PeriodicTimer
Klasa System.Threading.PeriodicTimer umożliwia oczekiwanie na poszczególne znaczniki określonego interwału, wykonując pracę po wywołaniu metody PeriodicTimer.WaitForNextTickAsync.
Podczas tworzenia System.Threading.PeriodicTimer obiektu należy określić, TimeSpan który określa długość czasu między poszczególnymi znacznikami czasomierza. Zamiast przekazywać wywołanie zwrotne lub ustawiać program obsługi zdarzeń, tak jak w poprzednich klasach czasomierza, należy wykonać pracę bezpośrednio w zakresie, oczekując WaitForNextTickAsync na postęp czasomierza przez określony interwał.
Metoda WaitForNextTickAsync zwraca wartość ; true
po pomyślnym uruchomieniu czasomierza i false
po anulowaniu czasomierza przez wywołanie metody PeriodicTimer.DisposeValueTask<bool>
. WaitForNextTickAsync opcjonalnie akceptuje element CancellationToken, co powoduje TaskCanceledException żądanie anulowania.
Aby uzyskać więcej informacji, zobacz System.Threading.PeriodicTimer.