È una cattiva forma da usare this
nelle istruzioni di blocco perché è generalmente fuori dal tuo controllo chi altro potrebbe bloccare quell'oggetto.
Al fine di pianificare correttamente le operazioni parallele, è necessario prestare particolare attenzione a considerare possibili situazioni di deadlock e la presenza di un numero sconosciuto di punti di ingresso di blocco lo ostacola. Ad esempio, chiunque abbia un riferimento all'oggetto può bloccarlo senza che il progettista / creatore di oggetti lo sappia. Ciò aumenta la complessità delle soluzioni multi-thread e potrebbe comprometterne la correttezza.
Un campo privato è di solito un'opzione migliore in quanto il compilatore imporrà restrizioni di accesso ad esso e incapsulerà il meccanismo di blocco. L'uso della this
violazione incapsula esponendo al pubblico parte dell'implementazione del blocco. Inoltre, non è chiaro che acquisirai un blocco a this
meno che non sia stato documentato. Anche in questo caso, affidarsi alla documentazione per prevenire un problema non è ottimale.
Infine, esiste un malinteso comune che lock(this)
modifica effettivamente l'oggetto passato come parametro e in qualche modo lo rende di sola lettura o inaccessibile. Questo è falso . L'oggetto passato come parametro lock
serve semplicemente come chiave . Se è già presente un blocco su quella chiave, non è possibile effettuare il blocco; in caso contrario, il blocco è consentito.
Questo è il motivo per cui è male usare le stringhe come chiavi nelle lock
istruzioni, dal momento che sono immutabili e sono condivise / accessibili attraverso parti dell'applicazione. Dovresti invece usare una variabile privata, Object
un'istanza andrà bene.
Esegui il seguente codice C # come esempio.
public class Person
{
public int Age { get; set; }
public string Name { get; set; }
public void LockThis()
{
lock (this)
{
System.Threading.Thread.Sleep(10000);
}
}
}
class Program
{
static void Main(string[] args)
{
var nancy = new Person {Name = "Nancy Drew", Age = 15};
var a = new Thread(nancy.LockThis);
a.Start();
var b = new Thread(Timewarp);
b.Start(nancy);
Thread.Sleep(10);
var anotherNancy = new Person { Name = "Nancy Drew", Age = 50 };
var c = new Thread(NameChange);
c.Start(anotherNancy);
a.Join();
Console.ReadLine();
}
static void Timewarp(object subject)
{
var person = subject as Person;
if (person == null) throw new ArgumentNullException("subject");
// A lock does not make the object read-only.
lock (person.Name)
{
while (person.Age <= 23)
{
// There will be a lock on 'person' due to the LockThis method running in another thread
if (Monitor.TryEnter(person, 10) == false)
{
Console.WriteLine("'this' person is locked!");
}
else Monitor.Exit(person);
person.Age++;
if(person.Age == 18)
{
// Changing the 'person.Name' value doesn't change the lock...
person.Name = "Nancy Smith";
}
Console.WriteLine("{0} is {1} years old.", person.Name, person.Age);
}
}
}
static void NameChange(object subject)
{
var person = subject as Person;
if (person == null) throw new ArgumentNullException("subject");
// You should avoid locking on strings, since they are immutable.
if (Monitor.TryEnter(person.Name, 30) == false)
{
Console.WriteLine("Failed to obtain lock on 50 year old Nancy, because Timewarp(object) locked on string \"Nancy Drew\".");
}
else Monitor.Exit(person.Name);
if (Monitor.TryEnter("Nancy Drew", 30) == false)
{
Console.WriteLine("Failed to obtain lock using 'Nancy Drew' literal, locked by 'person.Name' since both are the same object thanks to inlining!");
}
else Monitor.Exit("Nancy Drew");
if (Monitor.TryEnter(person.Name, 10000))
{
string oldName = person.Name;
person.Name = "Nancy Callahan";
Console.WriteLine("Name changed from '{0}' to '{1}'.", oldName, person.Name);
}
else Monitor.Exit(person.Name);
}
}
Uscita console
'this' person is locked!
Nancy Drew is 16 years old.
'this' person is locked!
Nancy Drew is 17 years old.
Failed to obtain lock on 50 year old Nancy, because Timewarp(object) locked on string "Nancy Drew".
'this' person is locked!
Nancy Smith is 18 years old.
'this' person is locked!
Nancy Smith is 19 years old.
'this' person is locked!
Nancy Smith is 20 years old.
Failed to obtain lock using 'Nancy Drew' literal, locked by 'person.Name' since both are the same object thanks to inlining!
'this' person is locked!
Nancy Smith is 21 years old.
'this' person is locked!
Nancy Smith is 22 years old.
'this' person is locked!
Nancy Smith is 23 years old.
'this' person is locked!
Nancy Smith is 24 years old.
Name changed from 'Nancy Drew' to 'Nancy Callahan'.