Pourquoi l'objet de verrouillage doit-il être statique?

112

Il est très courant d'utiliser un objet statique privé en lecture seule pour le verrouillage en multi threading. Je comprends que le privé réduit les points d'entrée à l'objet de verrouillage en resserrant l'encapsulation et donc l'accès au plus essentiel.

Mais pourquoi statique?

private static readonly object Locker = new object();

À la fin, le champ n'est utilisé que dans ma classe uniquement, et je pourrais également l'utiliser à la place:

private readonly object Locker = new object();

Des commentaires?

METTRE À JOUR:

A titre d'exemple, j'ai collé ce code (juste un exemple). Je pourrais utiliser un casier statique ou non statique à ce sujet et les deux fonctionneraient bien. Compte tenu de la réponse ci-dessous, je devrais plutôt définir mon casier comme ça? (Désolé, j'ai une interview la semaine prochaine et j'ai besoin de connaître chaque détail :)

private readonly object Locker = new object();

Et voici le code:

    private int _priceA;
    private int _priceB;
    private EventWaitHandle[] _waithandle;
    private readonly IService _service;

//ctor
public ModuleAViewModel(IService service)
    {
        _service = service;
        _modelA = new ModelA();
        _waithandle = new ManualResetEvent[2];
        _waithandle[0] = new ManualResetEvent(false);
        _waithandle[1] = new ManualResetEvent(false);
        LoadDataByThread();
    }


 private void LoadDataByThread()
        {
            new Thread(() =>
                           {
                               new Thread(() =>
                               {
                                   lock (Locker)
                                   {
                                       _priceA = _service.GetPriceA();
                                   }
                                   _waithandle[0].Set();
                               }).Start();

                               new Thread(() =>
                               {
                                   lock (Locker)
                                   {
                                       _priceB = _service.GetPriceB();
                                   }
                                   _waithandle[1].Set();
                               }).Start();

                               WaitHandle.WaitAll(_waithandle);
                               PriceA = _priceA;
                               PriceB = _priceB;
                           }).Start();
        }

Merci

Houman
la source
15
À ma connaissance, statique est généralement utilisé pour le rendre indépendant de l'instance. Si plusieurs instances de "MyWorkerClass" existent, une seule peut s'exécuter avec les données données à la fois (en supposant qu'elles utilisent toutes des ressources partagées).
Brad Christie
2
Le montage manque d'un détail important: où sont _serviceet _waithandlesitués? exemple? statique? autre? Cela pourrait , par exemple, être délibérément synchroniser l'accès à un serveur distant ...
Marc Gravell
à droite, avec la deuxième modification: oui, à partir de cette fin, vous pouvez verrouiller par instance. Il peut y avoir eu des raisons de le rendre statique, cependant - si le développeur d'origine voulait (comme mentionné) synchroniser l'accès afin que le serveur ne reçoive qu'une seule requête à la fois de cet AppDomain ... je ne peux pas savoir si c'est le cas , ou si c'était simplement accidentel.
Marc Gravell

Réponses:

177

Il n'est pas "très courant d'utiliser un objet statique privé en lecture seule pour verrouiller en multi threading" - plutôt, il est courant d'utiliser un verrou à la granularité appropriée / choisie . Parfois c'est static. Le plus souvent, l'OMI, ce n'est pas le cas - mais il est basé sur une instance .

La principale fois que vous voyez un staticverrou est pour un cache global, ou pour le chargement différé de données globales / singletons. Et dans ce dernier, il y a de meilleures façons de le faire de toute façon .

Cela dépend donc vraiment: comment est-il Lockerutilisé dans votre scénario? Protège-t-il quelque chose qui est lui - même statique? Si tel est le cas, le verrou doit être statique. S'il protège quelque chose qui est basé sur une instance , alors IMO le verrou doit également être basé sur une instance.

Marc Gravell
la source
24
Pourriez-vous donner plus de détails sur une meilleure façon de différer le chargement des données globales?
bizi
J'utilise toujours un static / volatile car s'il y a plusieurs endroits où il est basé sur une instance, je voudrais toujours contrôler ma méthode / variable accédée d'une manière thread-safe. De nombreuses instances peuvent accéder aux mêmes ressources et je souhaite contrôler cela. Moi aussi, j'aimerais voir le mieux de faire cela. Vous avez un excellent représentant et je suis sûr que votre réponse sera tout aussi formidable pour moi. Répondez, s'il vous plaît?
Andrew Simpson
82

Il n'est pas nécessaire que ce soit statique, en fait parfois, il ne devrait pas être statique.

La variable doit vivre dans la même portée que les méthodes où vous l'utilisez pour le verrouillage. Si les méthodes sont statiques, la variable doit être statique, et si les méthodes sont des méthodes d'instance, la variable doit être une variable d'instance.

Une variable statique fonctionnera toujours lorsqu'elle est utilisée pour verrouiller une méthode d'instance, mais vous serez alors trop verrouillée. Vous verrouillez toutes les méthodes dans toutes les instances, pas seulement les méthodes de la même instance.

Guffa
la source
28
+1 pour le "a-ha" ... Vous verrouillez toutes les méthodes dans toutes les instances, pas seulement les méthodes de la même instance.
radarbob
3
@radarbob - Détail mineur: Vous ne verrouillez pas toutes les méthodes, vous prenez simplement un verrou qui pourrait intéresser plus de clients. Les méthodes ne sont jamais verrouillées, c'est juste que le mutex a été pris.
Erno
Je soupçonne que la formulation de cette réponse pourrait être trompeuse - le verrouillage ne devrait rien avoir à voir avec la portée des méthodes - il ne devrait concerner que la portée des données partagées auxquelles ces méthodes ont accès. La méthode d'instance peut ne pas accéder à des données partagées (et donc pas besoin de verrouillage), peut accéder à des données partagées statiques (et donc avoir besoin d'un verrou statique, le refactoring peut également être une bonne idée à la place), même chose pour statique ...
Alexei Levenkov
@AlexeiLevenkov: Vous avez raison de dire que la portée doit en fait être décidée selon que les données sont statiques ou non, mais la portée des méthodes doit également être décidée par cela, de sorte que tout s'emboîte. Les données d'instance n'ont normalement pas besoin de verrouillage, mais si l'instance est partagée entre les threads, vous aurez besoin d'un verrouillage.
Guffa
28

La portée et la durée de vie d'un verrou peuvent / doivent dépendre de la «chose» que vous souhaitez verrouiller. Les verrous statiques sont principalement utilisés pour verrouiller les objets statiques.

Euh non
la source
3
Détail mineur: le verrou n'est pas statique, l'objet que vous utilisez pour identifier le verrou est statique. Un autre détail mineur: vous ne verrouillez pas les «choses».
Guffa le
2
Oui, je pense que si nous essayons de verrouiller les mauvaises «choses», elles peuvent être trop grandes et trop fortes, et un jour s'échapper.
ProfK
12
@Guffa C'est étrange, dans un commentaire ci-dessus, vous avez dit à juste titre: "Vous êtes juste en train de trop compliquer les choses", maintenant je vois 1 min avant de dire cela, il semble que vous compliquiez les choses :)
Nicholas Petersen