Timer Timer Timer Timer Class

Definizione

Genera un evento dopo un intervallo specificato, con un'opzione per generare eventi ricorrenti.Generates an event after a set interval, with an option to generate recurring events.

public ref class Timer : System::ComponentModel::Component, System::ComponentModel::ISupportInitialize
public class Timer : System.ComponentModel.Component, System.ComponentModel.ISupportInitialize
type Timer = class
    inherit Component
    interface ISupportInitialize
Public Class Timer
Inherits Component
Implements ISupportInitialize
Ereditarietà
Implementazioni

Esempi

Nell'esempio seguente viene creata un' System.Timers.Timer istanza di un oggetto Timer.Elapsed che genera il relativo evento ogni due secondi (2.000 millisecondi), imposta un gestore eventi per l'evento e avvia il timer.The following example instantiates a System.Timers.Timer object that fires its Timer.Elapsed event every two seconds (2,000 milliseconds), sets up an event handler for the event, and starts the timer. Il gestore eventi Visualizza il valore della ElapsedEventArgs.SignalTime proprietà ogni volta che viene generato.The event handler displays the value of the ElapsedEventArgs.SignalTime property each time it is raised.

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...
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...

Commenti

Il Timer componente è un timer basato su server che genera un Elapsed evento nell'applicazione dopo che è trascorso il numero Interval di millisecondi nella proprietà.The Timer component is a server-based timer that raises an Elapsed event in your application after the number of milliseconds in the Interval property has elapsed. È possibile configurare l' Timer oggetto per generare l'evento una sola volta o ripetutamente AutoReset utilizzando la proprietà.You can configure the Timer object to raise the event just once or repeatedly using the AutoReset property. In genere, Timer un oggetto viene dichiarato a livello di classe in modo che rimanga nell'ambito purché sia necessario.Typically, a Timer object is declared at the class level so that it stays in scope as long as it is needed. È quindi possibile gestire il Elapsed relativo evento per fornire un'elaborazione regolare.You can then handle its Elapsed event to provide regular processing. Si supponga, ad esempio, di disporre di un server critico che deve essere mantenuto in esecuzione 24 ore al giorno, 7 giorni alla settimana.For example, suppose you have a critical server that must be kept running 24 hours a day, 7 days a week. È possibile creare un servizio che usa un Timer oggetto per controllare periodicamente il server e verificare che il sistema sia attivo e in esecuzione.You could create a service that uses a Timer object to periodically check the server and ensure that the system is up and running. Se il sistema non risponde, il servizio potrebbe provare a riavviare il server o a inviare una notifica all'amministratore.If the system is not responding, the service could attempt to restart the server or notify an administrator.

Importante

La Timer classe non è disponibile per tutte le implementazioni e le versioni di .NET, ad esempio .NET standard 1,6 e versioni precedenti.The Timer class is not available for all .NET implementations and versions, such as .NET Standard 1.6 and lower versions. In questi casi, è invece possibile usare System.Threading.Timer la classe.In these cases, you can use the System.Threading.Timer class instead.

Il tipo implementa l'interfaccia IDisposable.This type implements the IDisposable interface. Dopo aver utilizzato il tipo, è necessario eliminarlo direttamente o indirettamente.When you have finished using the type, you should dispose of it either directly or indirectly. Per eliminare direttamente il tipo, chiamare il metodo Dispose in un blocco try/catch.To dispose of the type directly, call its Dispose method in a try/catch block. Per eliminarlo indirettamente, utilizzare un costrutto di linguaggio come ad esempio using in C# o Using in Visual Basic.To dispose of it indirectly, use a language construct such as using (in C#) or Using (in Visual Basic). Per altre informazioni, vedere la sezione "Uso di un oggetto che implementa IDisposable" nell'argomento relativo all'interfaccia IDisposable.For more information, see the "Using an Object that Implements IDisposable" section in the IDisposable interface topic.

La classe basata su System.Timers.Timer server è progettata per essere usata con i thread di lavoro in un ambiente multithread.The server-based System.Timers.Timer class is designed for use with worker threads in a multithreaded environment. I timer del server possono spostarsi tra i thread per Elapsed gestire l'evento generato, ottenendo una maggiore precisione rispetto ai timer di Windows per la generazione dell'evento nel tempo.Server timers can move among threads to handle the raised Elapsed event, resulting in more accuracy than Windows timers in raising the event on time.

Il System.Timers.Timer componente genera l' Elapsed evento in base al valore (in Interval millisecondi) della proprietà.The System.Timers.Timer component raises the Elapsed event, based on the value (in milliseconds) of the Interval property. È possibile gestire questo evento per eseguire l'elaborazione necessaria.You can handle this event to perform the processing you need. Si supponga, ad esempio, di disporre di un'applicazione di vendita online che invii costantemente gli ordini di vendita a un database.For example, suppose that you have an online sales application that continuously posts sales orders to a database. Il servizio che compila le istruzioni per la spedizione opera su un batch di ordini anziché elaborare singolarmente ogni ordine.The service that compiles the instructions for shipping operates on a batch of orders rather than processing each order individually. È possibile usare un Timer per avviare l'elaborazione batch ogni 30 minuti.You could use a Timer to start the batch processing every 30 minutes.

Importante

La classe System. Timers. timer ha la stessa risoluzione del clock di sistema.The System.Timers.Timer class has the same resolution as the system clock. Ciò significa che l' Elapsed evento viene attivato a un intervallo definito dalla risoluzione del clock di sistema se la Interval proprietà è minore della risoluzione del clock di sistema.This means that the Elapsed event will fire at an interval defined by the resolution of the system clock if the Interval property is less than the resolution of the system clock. Per altre informazioni, vedere la proprietà Interval.For more information, see the Interval property.

Quando AutoReset è impostato su false, un System.Timers.Timer oggetto genera l' Elapsed evento solo una volta, dopo che Interval il primo è scaduto.When AutoReset is set to false, a System.Timers.Timer object raises the Elapsed event only once, after the first Interval has elapsed. Per generare regolarmente l' Elapsed evento a intervalli definiti dall'oggetto Interval, impostare AutoReset su true, che rappresenta il valore predefinito.To keep raising the Elapsed event regularly at the interval defined by the Interval, set AutoReset to true, which is the default value.

Il Timer componente intercetta ed Elimina tutte le eccezioni generate dai gestori eventi per l' Elapsed evento.The Timer component catches and suppresses all exceptions thrown by event handlers for the Elapsed event. Questo comportamento è soggetto a modifiche nelle versioni future del .NET Framework.This behavior is subject to change in future releases of the .NET Framework. Si noti, tuttavia, che questo non è vero per i gestori eventi che vengono eseguiti in modo asincrono await e includono l' C#operatore (in Await ) o l'operatore (in Visual Basic).Note, however, that this is not true of event handlers that execute asynchronously and include the await operator (in C#) or the Await operator (in Visual Basic). Le eccezioni generate in questi gestori eventi vengono propagate al thread chiamante, come illustrato nell'esempio seguente.Exceptions thrown in these event handlers are propagated back to the calling thread, as the following example illustrates. Per ulteriori informazioni sulle eccezioni generate nei metodi asincroni, vedere gestione delle eccezioni.For more information on exceptions thrown in asynchronous methods, see Exception Handling.

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

class Example
{
   static void Main()
   {
      Timer timer = new Timer(1000);
      timer.Elapsed += async ( sender, e ) => await HandleTimer();
      timer.Start();
      Console.Write("Press any key to exit... ");
      Console.ReadKey();
   }

   private static Task HandleTimer()
   {
     Console.WriteLine("\nHandler not implemented..." );
     throw new NotImplementedException();
   }
}
// The example displays output like the following:
//   Press any key to exit...
//   Handler not implemented...
//   
//   Unhandled Exception: System.NotImplementedException: The method or operation is not implemented.
//      at Example.HandleTimer()
//      at Example.<<Main>b__0>d__2.MoveNext()
//   --- End of stack trace from previous location where exception was thrown ---
//      at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<>c__DisplayClass2.<ThrowAsync>b__5(Object state)
//      at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
//      at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
//      at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
//      at System.Threading.ThreadPoolWorkQueue.Dispatch()
Imports System.Threading.Tasks
Imports System.Timers

Public Module Example
   Public Sub Main()
      Dim timer As New Timer(1000)  
      AddHandler timer.Elapsed, AddressOf Example.HandleTimer     
      'timer.Elapsed = Async ( sender, e ) => await HandleTimer()
      timer.Start()
      Console.Write("Press any key to exit... ")
      Console.ReadKey()
   End Sub

   Private Async Sub HandleTimer(sender As Object, e As EventArgs)
      Await Task.Run(Sub()
                        Console.WriteLine()
                        Console.WriteLine("Handler not implemented..." )
                        Throw New NotImplementedException()
                     End Sub)   
   End Sub
End Module
' The example displays output like the following:
'   Press any key to exit...
'   Handler not implemented...
'   
'   Unhandled Exception: System.NotImplementedException: The method or operation is not implemented.
'      at Example._Lambda$__1()
'      at System.Threading.Tasks.Task.Execute()
'   --- End of stack trace from previous location where exception was thrown ---
'      at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
'      at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
'      at Example.VB$StateMachine_0_HandleTimer.MoveNext()
'   --- End of stack trace from previous location where exception was thrown ---
'      at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<>c__DisplayClass2.<ThrowAsync>b__5(Object state)
'      at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
'      at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
'      at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
'      at System.Threading.ThreadPoolWorkQueue.Dispatch()

Se la SynchronizingObject proprietà è null, l' Elapsed evento viene generato in un ThreadPool thread.If the SynchronizingObject property is null, the Elapsed event is raised on a ThreadPool thread. Se l' Elapsed elaborazione dell'evento dura più a Intervallungo, è possibile che l'evento venga generato ThreadPool nuovamente in un altro thread.If processing of the Elapsed event lasts longer than Interval, the event might be raised again on another ThreadPool thread. In questa situazione, il gestore eventi deve essere rientrante.In this situation, the event handler should be reentrant.

Nota

Il metodo di gestione degli eventi può essere eseguito in un thread nello stesso momento in cui un altro Stop thread chiama il metodo Enabled o imposta falsela proprietà su.The event-handling method might run on one thread at the same time that another thread calls the Stop method or sets the Enabled property to false. Questo potrebbe causare l' Elapsed evento generato dopo l'arresto del timer.This might result in the Elapsed event being raised after the timer is stopped. Il codice di esempio per Stop il metodo Mostra un modo per evitare questo race condition.The example code for the Stop method shows one way to avoid this race condition.

Anche se SynchronizingObject non nullè, Elapsed gli eventi possono verificarsi dopo Dispose che Stop è stato chiamato il metodo o o Enabled dopo che la proprietà è falsestata impostata su, perché il segnale per generare l'oggetto Elapsed l'evento viene sempre accodato per l'esecuzione in un thread del pool di thread.Even if SynchronizingObject is not null, Elapsed events can occur after the Dispose or Stop method has been called or after the Enabled property has been set to false, because the signal to raise the Elapsed event is always queued for execution on a thread pool thread. Un modo per risolvere questo race condition consiste nell'impostare un flag che indichi al gestore Elapsed dell'evento di ignorare gli eventi successivi.One way to resolve this race condition is to set a flag that tells the event handler for the Elapsed event to ignore subsequent events.

Se si usa la System.Timers.Timer classe con un elemento dell'interfaccia utente, ad esempio un form o un controllo, senza posizionare il timer sull'elemento dell'interfaccia utente, assegnare il form o il controllo Timer che contiene SynchronizingObject l'oggetto alla proprietà, in modo che l'evento sia marshalling al thread dell'interfaccia utente.If you use the System.Timers.Timer class with a user interface element, such as a form or control, without placing the timer on that user interface element, assign the form or control that contains the Timer to the SynchronizingObject property, so that the event is marshaled to the user interface thread.

Per un elenco di valori di proprietà predefiniti per un'istanza Timerdi, vedere Timer il costruttore.For a list of default property values for an instance of Timer, see the Timer constructor.

Suggerimento

Tenere presente che .NET include quattro classi denominate Timer, ognuna delle quali offre funzionalità diverse:Be aware that .NET includes four classes named Timer, each of which offers different functionality:

  • System.Timers.Timer(questo argomento): genera un evento a intervalli regolari.System.Timers.Timer (this topic): fires an event at regular intervals. La classe è destinata all'uso come componente basato su server o servizio in un ambiente a thread multipli. non dispone di interfaccia utente e non è visibile in fase di esecuzione.The class is intended for use as a server-based or service component in a multithreaded environment; it has no user interface and is not visible at runtime.
  • System.Threading.Timer: esegue un singolo metodo di callback in un thread del pool a intervalli regolari.System.Threading.Timer: executes a single callback method on a thread pool thread at regular intervals. Il metodo di callback viene definito quando viene creata un'istanza del timer e non può essere modificato.The callback method is defined when the timer is instantiated and cannot be changed. Analogamente System.Timers.Timer alla classe, questa classe è destinata all'uso come componente basato su server o servizio in un ambiente a thread multipli. non dispone di interfaccia utente e non è visibile in fase di esecuzione.Like the System.Timers.Timer class, this class is intended for use as a server-based or service component in a multithreaded environment; it has no user interface and is not visible at runtime.
  • System.Windows.Forms.Timer(Solo .NET Framework): un componente Windows Forms che genera un evento a intervalli regolari.System.Windows.Forms.Timer (.NET Framework only): a Windows Forms component that fires an event at regular intervals. Il componente non dispone di interfacce utente ed è progettato per l'uso in un ambiente a thread singolo.The component has no user interface and is designed for use in a single-threaded environment.
  • System.Web.UI.Timer(Solo .NET Framework): componente ASP.NET che esegue postback asincroni o sincroni di pagine Web a intervalli regolari.System.Web.UI.Timer (.NET Framework only): an ASP.NET component that performs asynchronous or synchronous web page postbacks at a regular interval.

Costruttori

Timer() Timer() Timer() Timer()

Inizializza una nuova istanza della classe Timer e imposta tutte le proprietà sui rispettivi valori iniziali.Initializes a new instance of the Timer class, and sets all the properties to their initial values.

Timer(Double) Timer(Double) Timer(Double) Timer(Double)

Inizializza una nuova istanza della classe Timer e imposta la proprietà Interval sul numero di millisecondi specificato.Initializes a new instance of the Timer class, and sets the Interval property to the specified number of milliseconds.

Proprietà

AutoReset AutoReset AutoReset AutoReset

Ottiene o imposta un valore booleano che indica se Timer deve generare l'evento Elapsed una sola volta (false) o più volte (true).Gets or sets a Boolean indicating whether the Timer should raise the Elapsed event only once (false) or repeatedly (true).

CanRaiseEvents CanRaiseEvents CanRaiseEvents CanRaiseEvents

Ottiene un valore che indica se il componente può generare un evento.Gets a value indicating whether the component can raise an event.

(Inherited from Component)
Container Container Container Container

Ottiene il IContainer che contiene il Component.Gets the IContainer that contains the Component.

(Inherited from Component)
DesignMode DesignMode DesignMode DesignMode

Ottiene un valore che indica se il Component si trova in modalità progettazione.Gets a value that indicates whether the Component is currently in design mode.

(Inherited from Component)
Enabled Enabled Enabled Enabled

Ottiene o imposta un valore che indica se Timer deve generare l'evento Elapsed.Gets or sets a value indicating whether the Timer should raise the Elapsed event.

Events Events Events Events

Ottiene l'elenco dei gestori eventi allegati a questo Component.Gets the list of event handlers that are attached to this Component.

(Inherited from Component)
Interval Interval Interval Interval

Ottiene o imposta l'intervallo, espresso in millisecondi, in cui generare l'evento Elapsed.Gets or sets the interval, expressed in milliseconds, at which to raise the Elapsed event.

Site Site Site Site

Ottiene o imposta il sito che associa l'oggetto Timer al contenitore in modalità progettazione.Gets or sets the site that binds the Timer to its container in design mode.

SynchronizingObject SynchronizingObject SynchronizingObject SynchronizingObject

Ottiene o imposta l'oggetto usato per effettuare il marshalling delle chiamate del gestore eventi generate alla scadenza di un intervallo.Gets or sets the object used to marshal event-handler calls that are issued when an interval has elapsed.

Metodi

BeginInit() BeginInit() BeginInit() BeginInit()

Avvia l'inizializzazione in fase di esecuzione di un oggetto Timer usato in un form o da un altro componente.Begins the run-time initialization of a Timer that is used on a form or by another component.

Close() Close() Close() Close()

Rilascia le risorse usate da Timer.Releases the resources used by the Timer.

CreateObjRef(Type) CreateObjRef(Type) CreateObjRef(Type) CreateObjRef(Type)

Consente di creare un oggetto che contiene tutte le informazioni rilevanti necessarie per la generazione del proxy utilizzato per effettuare la comunicazione con un oggetto remoto.Creates an object that contains all the relevant information required to generate a proxy used to communicate with a remote object.

(Inherited from MarshalByRefObject)
Dispose() Dispose() Dispose() Dispose()

Rilascia tutte le risorse usate da Component.Releases all resources used by the Component.

(Inherited from Component)
Dispose(Boolean) Dispose(Boolean) Dispose(Boolean) Dispose(Boolean)

Rilascia tutte le risorse usate dall'oggetto Timer corrente.Releases all resources used by the current Timer.

EndInit() EndInit() EndInit() EndInit()

Termina l'inizializzazione in fase di esecuzione di un oggetto Timer usato in un form o da un altro componente.Ends the run-time initialization of a Timer that is used on a form or by another component.

Equals(Object) Equals(Object) Equals(Object) Equals(Object)

Determina se l'oggetto specificato è uguale all'oggetto corrente.Determines whether the specified object is equal to the current object.

(Inherited from Object)
GetHashCode() GetHashCode() GetHashCode() GetHashCode()

Funge da funzione hash predefinita.Serves as the default hash function.

(Inherited from Object)
GetLifetimeService() GetLifetimeService() GetLifetimeService() GetLifetimeService()

Consente di recuperare l'oggetto servizio di durata corrente per controllare i criteri di durata per l'istanza.Retrieves the current lifetime service object that controls the lifetime policy for this instance.

(Inherited from MarshalByRefObject)
GetService(Type) GetService(Type) GetService(Type) GetService(Type)

Consente di restituire un oggetto che rappresenta un servizio fornito da Component o dal relativo Container.Returns an object that represents a service provided by the Component or by its Container.

(Inherited from Component)
GetType() GetType() GetType() GetType()

Ottiene l'oggetto Type dell'istanza corrente.Gets the Type of the current instance.

(Inherited from Object)
InitializeLifetimeService() InitializeLifetimeService() InitializeLifetimeService() InitializeLifetimeService()

Ottiene un oggetto servizio di durata per controllare i criteri di durata per questa istanza.Obtains a lifetime service object to control the lifetime policy for this instance.

(Inherited from MarshalByRefObject)
MemberwiseClone() MemberwiseClone() MemberwiseClone() MemberwiseClone()

Crea una copia superficiale dell'oggetto Object corrente.Creates a shallow copy of the current Object.

(Inherited from Object)
MemberwiseClone(Boolean) MemberwiseClone(Boolean) MemberwiseClone(Boolean) MemberwiseClone(Boolean)

Crea una copia dei riferimenti dell'oggetto MarshalByRefObject corrente.Creates a shallow copy of the current MarshalByRefObject object.

(Inherited from MarshalByRefObject)
Start() Start() Start() Start()

Avvia la generazione dell'evento Elapsed impostando Enabled su true.Starts raising the Elapsed event by setting Enabled to true.

Stop() Stop() Stop() Stop()

Arresta la generazione dell'evento Elapsed impostando Enabled su false.Stops raising the Elapsed event by setting Enabled to false.

ToString() ToString() ToString() ToString()

Restituisce un oggetto String che contiene il nome dell'eventuale oggetto Component.Returns a String containing the name of the Component, if any. Questo metodo non deve essere sottoposto a override.This method should not be overridden.

(Inherited from Component)

Eventi

Disposed Disposed Disposed Disposed

Si verifica quando il componente viene eliminato da una chiamata al metodo Dispose().Occurs when the component is disposed by a call to the Dispose() method.

(Inherited from Component)
Elapsed Elapsed Elapsed Elapsed

Si verifica quando l'intervallo scade.Occurs when the interval elapses.

Si applica a

Thread safety

Tutti i static membri pubblici di questo tipo sono thread-safe.Any public static members of this type are thread safe. I membri di istanza non sono garantiti come thread-safe.Any instance members are not guaranteed to be thread safe.

Vedi anche