Minuteurs
.NET propose trois minuteurs à utiliser dans un environnement multithread :
- System.Threading.Timer, qui exécute une méthode de rappel unique sur un thread ThreadPool à intervalles réguliers.
- System.Timers.Timer qui, par défaut, déclenche un événement sur un thread ThreadPool à intervalles réguliers.
- System.Threading.PeriodicTimer, qui permet à l’appelant d’effectuer un travail après avoir attendu des cycles individuels du minuteur.
Notes
Certaines implémentations .NET peuvent inclure des minuteurs supplémentaires :
- System.Windows.Forms.Timer : composant Windows Forms qui déclenche un événement à intervalles réguliers. Le composant ne possède pas d’interface utilisateur et est conçu pour une utilisation dans un environnement à thread unique.
- System.Web.UI.Timer : composant ASP.NET qui effectue des publications (postback) de pages web asynchrones ou synchrones à intervalles réguliers.
- System.Windows.Threading.DispatcherTimer : minuteur intégré à la file d’attente Dispatcher qui est traitée selon un intervalle de temps et une priorité spécifiés.
Classe System.Threading.Timer
La classe System.Threading.Timer vous permet d’appeler en permanence un délégué à des intervalles de temps spécifiés. Vous pouvez aussi utiliser cette classe pour planifier un appel unique à un délégué dans un intervalle de temps spécifié. Le délégué est exécuté sur un thread ThreadPool.
Quand vous créez un objet System.Threading.Timer, vous spécifiez un délégué TimerCallback qui définit la méthode de rappel, un objet d’état facultatif qui est passé au rappel, la durée d’attente avant la première invocation du rappel et l’intervalle de temps entre les invocations de rappel. Pour annuler un minuteur en attente, appelez la méthode Timer.Dispose.
L’exemple suivant crée un minuteur qui appelle le délégué fourni au bout d’une seconde (1000 millisecondes) la première fois et ensuite toutes les deux secondes. L’objet d’état de l’exemple sert à compter le nombre de fois que le délégué est appelé. Le minuteur s’arrête dès que le délégué a été appelé au moins 10 fois.
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
Pour plus d’informations et d’exemples, consultez System.Threading.Timer.
Classe System.Timers.Timer
L’autre minuteur qui peut être utilisé dans un environnement multithread est System.Timers.Timer qui, par défaut, déclenche un événement sur un thread ThreadPool.
Au moment de créer un objet System.Timers.Timer, vous pouvez spécifier l’intervalle de temps au cours duquel un événement Elapsed est déclenché. Utilisez la propriété Enabled pour indiquer si un minuteur doit déclencher un événement Elapsed. Si vous avez besoin qu’un événement Elapsed soit déclenché une seule fois à l’issue de l’intervalle spécifié, définissez le AutoReset sur false
. La valeur par défaut de la propriété AutoReset est true
, ce qui signifie qu’un événement Elapsed est déclenché régulièrement selon l’intervalle défini par la propriété Interval.
Pour plus d’informations et d’exemples, consultez System.Timers.Timer.
System.Threading.PeriodicTimer, classe
La classe System.Threading.PeriodicTimer vous permet d’attendre des cycles individuels d’un intervalle spécifié, le travail étant effectué après l’appel de PeriodicTimer.WaitForNextTickAsync.
Quand vous créez un objet System.Threading.PeriodicTimer, vous spécifiez un TimeSpan qui détermine la durée entre chaque cycle du minuteur. Au lieu de passer un rappel ou de définir un gestionnaire d’événements comme pour les classes de minuteur précédentes, vous effectuez le travail directement dans l’étendue, en attendant que WaitForNextTickAsync fasse avancer le minuteur de l’intervalle spécifié.
La méthode WaitForNextTickAsync retourne un ValueTask<bool>
; true
en cas de déclenchement réussi du minuteur et false
quand le minuteur a été annulé par l’appel de PeriodicTimer.Dispose. WaitForNextTickAsync peut éventuellement accepter un CancellationToken, qui aboutit à une TaskCanceledException quand une annulation a été demandée.
Pour plus d’informations, consultez System.Threading.PeriodicTimer.