Lock o Monitor.Enter?

di Andrea Zani, in .NET,

In questi giorni ho avuto una pacifica(!?!?) discussione in privato sull'uso dei lock. Il Framework mette a disposizione varie classi per questa importante necessità. La più semplice è con l'uso del SyncLock di Visual Basic.Net (Lock {} in C#) o con la classe Monitor presente in System.Threading. Per vedere le differenze scriviamo due classi, la prima che utilizza il SyncLock di VB, la seconda direttamente la classe Monitor:

public class WithLock
public Conteggio as integer=0
public sub Aumenta()
SyncLock me
conteggio+=1
end synclock
end sub
end class<p />public class WithNoLock
public Conteggio as integer=0
public sub Aumenta()
Monitor.Enter(me)
conteggio+=1
Monitor.Exit(me)
end sub
end class

Ora a apriamo il Reflecton per vedere nella compilazione che cosa ha creato il Framework:

Puvlic class WithLock
Public Sub Aumenta()
 Dim lock1 As WithLock = Me
Monitor.Enter(lock1)
Try 
 Me.Conteggio = (Me.Conteggio + 1)
Return
 
Finally
 Monitor.Exit(lock1)
End Try
End Sub
End Class
Public Class WithNoLock
Public Sub Aumenta()
 Monitor.Enter(Me)
Me.Conteggio = (Me.Conteggio + 1)
Monitor.Exit(Me)
End Sub
End Class

Come si può vedere il Framework ha modificato la funzione del Visual Basic SyncLock nell'equivalente Monitor.Enter... Non c'è alcuna differenza dunque... be', una evidente c'è: nel caso dell'utilizzo della funzione SyncLock il framework ci garanrisce che il lock venga tolto alla fine del'elaborazione della funzione anche in presenza di errori nel blocco del codice all'interno del lock. Infatti, con l'utilizzo della classe Monitor si deve sempre essere certi di sbloccare il lock creato con l'Enter, altrimenti quella risorsa rimarrà bloccata in eterno, e il modo utilizzato dal Framework - l'inserimento della linea "Monitor.Exit()" nel blocco Finally ci garantisce questo.

Dunque sembra che il modo migliore sia l'utilizzo degli appositi comandi SyncLock e Lock {} di Visual Basic e C#. Ma è realmente così?

Nei casi reali, quante volte viene lasciato un blocco di codice importante - in cui si desidera utilizzare addirittura il lock delle risorse - senza una gestione personale degli errori? Rivediamo il codice d'esempio modificandolo con qualcosa di reale:

public class WithLock2
public Conteggio as integer=0
public sub Aumenta()
try
SyncLock me
conteggio+=1
end synclock
catch
' ....
end try
end sub
end class<p />public class WithNoLock2
public Conteggio as integer=0
public sub Aumenta()
try
Monitor.Enter(me)
conteggio+=1
catch
' ....
finally
Monitor.Exit(me)
end try
end sub
end class

Vediamo ora il codice prodotto dal Framework:

Public Class WithLock2
Public Sub Aumenta()
 Dim lock1 As WithLock2
Try 
 lock1 = Me
Monitor.Enter(lock1)
Try 
 Me.Conteggio = (Me.Conteggio + 1)
Return
 
Finally
 Monitor.Exit(lock1)
 
End Try
Return
 
Catch Exception exception1
 ProjectData.SetProjectError(exception1)
ProjectData.ClearProjectError
Return
End Try
End Sub
End Class

Addiriturra sono presenti due blocchi try... mentre nella versione il con Monitor nativo:

Public Class WithNoLock2
Public Sub Aumenta()
 Try 
 Monitor.Enter(Me)
Me.Conteggio = (Me.Conteggio + 1)
Return
 
Catch Exception exception1
 ProjectData.SetProjectError(exception1)
ProjectData.ClearProjectError
Return
 
Finally
 Monitor.Exit(Me)
 
End Try
End Sub
End Class

E' restata immutata, più veloce e più leggibile. Quali sono dunque le conclusioni di questo blog? Boh! Chi aveva ragione? Mah... :)

Uffa... non c'è neanche la tappa del giro d'Italia oggi...

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.

Nella stessa categoria
I più letti del mese