C'est mauvais d'utiliser this
dans les instructions lock parce qu'il est généralement hors de votre contrôle qui d'autre pourrait être de verrouillage sur cet objet.
Afin de bien planifier les opérations en parallèle, des précautions particulières doivent être prises afin d'envisager d'éventuelles situations de blocage, et d'avoir un nombre inconnu de verrouiller les points d'entrée qui empêche ce. Par exemple, l'une avec une référence à l'objet peut se verrouiller sur elle, sans que l'objet concepteur/créateur de savoir à ce sujet. Cela augmente la complexité de multi-thread solutions et peut nuire à leur exactitude.
Un champ privé est généralement une meilleure option que le compilateur va appliquer des restrictions d'accès, et il va encapsuler le mécanisme de verrouillage. À l'aide de this
viole l'encapsulation en exposant une partie de votre verrouillage de la mise en œuvre au public. Il n'est pas aussi clair que vous fera l'acquisition d'un verrou sur l' this
, sauf si elle a été documentée. Même puis, en s'appuyant sur la documentation de prévenir un problème est sous-optimale.
Enfin, il y a l'idée répandue qu' lock(this)
modifie en fait l'objet passé en paramètre, et d'une certaine façon fait en lecture seule ou inaccessibles. C'est faux. L'objet passé en paramètre à l' lock
sert seulement à la clé. Si un verrou est déjà en cours à cette clé, la serrure ne peut pas être fait; sinon, la serrure est autorisé.
C'est pourquoi il est mauvais d'utiliser les chaînes de caractères comme les touches en lock
des déclarations, étant donné qu'ils sont immuables et sont partagés/accessible à l'ensemble des parties de l'application. Vous devez utiliser une variable privée au lieu de cela, une Object
exemple fera très bien l'affaire.
Exécuter le code C# suivant comme un exemple.
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);
}
}
Sortie de la 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'.