Quando usare String.Intern: i Lock

String è un tipo immutabile che si basa sul pattern Flyweight: ogni volta creiamo una nuova stringa questa prenderà l’istanza memorizzata per quel valore. Un esempio pratico chiarisce tutto:

string s1 = "ciao";    // puntatore: p1
string s2 = "a tutti"; // puntatore: p2
string s3 = s1 + s2;  // puntatore: p3
string s4 = "ciao a tutti"; // puntatore: p3
s1 = s1 + s2; // puntatore: p1
s1 == s3; // true (verosimiglianza dall'override dell'operatore)
(object)s1 == (object)s3;  // false (confronto puntatori)
s1 = String.Inner(s1); // puntatore: p3
(object)s1 == (object)s3;  // true (confronto puntatori)

Questo per dare una spolveratina ai concetti. Il metodo String.Intern consente quindi di restituire il valore del puntatore memorizzato in cache. Ma a cosa può essere utile questa funzione?

 

Un utilizzo immediato risiede in ragioni di performance: confrontare puntatori è molto più efficiente che confrontare il contenuto. Avere quindi una collezione di stringhe con puntatori intern consente una comparazione molto più efficiente. Normalmente infatti l’approccio in una comparazione dovrebbe essere: per primo confronta i puntatori, altrimenti il contenuto.

Ma esiste un ulteriore utilizzo. Un utilizzo possibile sta nel lock: le funzioni di lock di .NET si basano infatti sul valore del puntatore per effettuare un lock. Immaginiamo quindi un lock di questo tipo:

lock((string)Session["username"]) {
    dbOperation1();
    dbOperation2();
}

Questo lock è sbagliato: infatti se lo stesso utente è collegato da un altro browser il lock potrebbe non essere acquisito. Il seguente metodo consente invece un lock corretto:

lock(String.Intern((string)Session["username"])) {
    dbOperation1();
    dbOperation2();
}

Si noti che questo approccio presuppone l’utilizzo di un unico web server. Se invece abbiamo in cluster differenti server, a seconda del server scelto potremmo avere differenti valori per il puntatore di “username” e l’approccio non sarebbe valido comunque.

 

Lascia un commento

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...