Utilizzare await all'interno di un metodo con lock

di Stefano Mostarda, in .NET Framework,

A volte capita di dover eseguire porzioni di codice che richiedono il lock su una risorsa e che quindi richiedono la sequenzializzazione dei thread che cercano di eseguire quel codice. Se, ad esempio, dovessimo scrivere su un file, non potremmo farlo simultaneamente da più thread altrimenti otterremmo errori di accesso concorrente.
La soluzione più semplice, anche se poco performante, è quella di acquisire un lock esclusivo all'inizio della scrittura e rilasciarlo quando abbiamo finito la scrittura così che un solo thread alla volta possa acquisire il lock mettendo in coda gli altri. Il modo più semplice per acquisire un lock è tramite l'istruzione lock di C# applicata su un oggetto statico.

static object lockobj = new();

lock (lockobj)
{
  //codice
}

Lo svantaggio di questa soluzione è che, all'interno di un blocco lock, non è possibile usare await pena un errore di compilazione. Essendo la scrittura un'operazione di I/O, non poter usare await è una grossa limitazione e quindi occorre trovare un'altra soluzione. La soluzione più comoda consiste nell'usare la classe SemaphoreSlim. Questa offre il metodo WaitAsync, che permette di acquisire un lock o di rimanere in attesa se un lock esiste già, e il metodo Release che rilascia il lock acquisito. vediamo nel prossimo esempio come usare questi metodi.

static readonly SemaphoreSlim sem = new(1, 1);

public async Task MethodAsync() 
{
  await sem.WaitAsync();
  try
  {
    //Codice
  }
  finally 
  {
    sem.Release();
  }
}

Come si intuisce dal codice, la prima cosa da fare è istanziare la classe SemaphoreSlim passando in input i valori 1 e 1 per garantire che solo un thread alla volta possa acquisire il lock. L'istanza la mettiamo poi in una variabile statica così che tutti i thread possano accedervi. Successivamente, nel codice del metodo acquisiamo il lock, o veniamo messi in coda se il lock è già stato acquisito da qualcuno, eseguiamo il codice e poi rilasciamo il lock nel blocco finally. Mettere il rilascio del lock in un blocco finally è fondamentale per garantire il corretto rilascio delle lock anche in presenza di un'eccezione a runtime.

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti

Nessuna risorsa collegata

I più letti di oggi