web-dev-qa-db-fra.com

C # Comment détecter un objet est déjà verrouillé

Comment puis-je détecter si un objet est verrouillé ou non?

Monitor.TryEnter (comme décrit dans Existe-t-il un moyen de détecter si un objet est verrouillé? ) ne fonctionne pas pour moi car il verrouille l'objet s'il n'est pas verrouillé.

Je seulement veux vérifier s'il est verrouillé et ailleurs dans mon code j'utiliserai la classe Monitor pour verrouiller l'objet.

Je sais qu'il est possible d'utiliser par exemple un champ booléen (par exemple private bool ObjectIsLocked) mais ce qu'il faut détecter à l'aide de l'objet verrou lui-même.

L'exemple de code ci-dessous montre ce que je veux faire:

private static object myLockObject = new object();

private void SampleMethod()
{
    if(myLockObject /*is not locked*/) // First check without locking it
    {
        ...
        // The object will be locked some later in the code
        if(!Monitor.TryEnter(myLockObject)) return;

        try
        {

            ....
        }
        catch(){...}
        finally
        {
            Monitor.Exit(myLockObject);
        }
    }
}
31
hwcverwe

Vous vous trompez. Si vous n'avez pas le verrou sur l'objet, vous ne pouvez pas vérifier s'il est verrouillé (et si vous avez le verrou, vous le saurez à l'avance). Vous pouvez "demander" "est verrouillé?" et obtenez un "non" comme réponse, puis à la nanoseconde suivante un autre thread peut prendre le verrou et votre programme entrera dans un état corrompu. Ce n'est tout simplement pas la voie à suivre pour les applications multithread et la raison pour laquelle .NET n'a pas de Monitor.IsLocked méthode. Si votre code doit vérifier le verrou avant de l'acquérir, vous avez donc un problème de conception. Essayer de le résoudre avec des indicateurs non protégés est une mauvaise solution qui est garantie par 100% des chances de ne pas fonctionner.

Quoi qu'il en soit, n'utilisez pas un bool var pour signaler que l'état multi-thread est verrouillé (car vous pouvez avoir le même problème, vous lisez "false" et 1 nanoseconde plus tard, un autre thread écrira "true"). Utilisation Interlock.CompareExchange.

private static int _lockFlag = 0; // 0 - free

if (Interlocked.CompareExchange(ref _lockFlag, 1, 0) == 0){
   // only 1 thread will enter here without locking the object/put the
   // other threads to sleep.

   Monitor.Enter(yourLockObject); 

   // free the lock.
   Interlocked.Decrement(ref _lockFlag);
}

Vous verrez que vous devrez changer le _lockFlag sur chaque endroit où un verrou sur votre objet pourrait être acquis. En d'autres termes, vous construirez un système de verrouillage personnalisé autour du système natif.

44
Marcelo De Zen

Monitor.IsEntered devrait faire l'affaire.

Edit: je viens de relire la documentation, et ça dit:

Détermine si le thread actuel détient le verrou sur l'objet spécifié.

Ce n'est donc pas suffisant, car vous aimeriez probablement savoir si un thread différent détient un verrou?

8
Pete

Il n'y a aucun moyen de le faire avec la classe Monitor en C #

Utilisez simplement;

    var lockedBySomeoneElse = !Monitor.TryEnter(obj);
    if (!lockedBySomeoneElse) Monitor.Exit(obj);
    // the variable 'lockedBySomeoneElse' has the info you want

D'autres verrous comme readerwriterlockslim n'aident pas vraiment. Celui-là peut vous dire comment les lecteurs peuvent être, mais pas s'il y a un écrivain occupé ;-(

aussi si vous utilisez votre propre suggestion "Private bool ObjectIsLocked", qui est la route que je prendrais, je pense, vous devriez utiliser

      private volatile bool ObjectIsLocked

Cela permettra à C # de mieux refléter les modifications avec les mises à jour multithread.

5
IvoTops

Techniquement, vous pouvez vérifier le champ Sync Block Index de l'objet qui a un index de la structure allouée paresseusement associée dans Sync Blocks array - chaque objet a ce champ et chaque objet, utilisé pour synchronziation, a ce champ défini. Ces structures sont utilisées pour coordonner la synchronisation des threads. Cependant, je doute fortement que vous puissiez accéder à ces informations sans API de profilage.

0
Andrey Taptunov

Si vous voulez vous assurer que l'objet est toujours verrouillable plus tard, appelez simplement TryEnter et maintenez le verrou tout le temps. Sinon, si vous voulez essayer de verrouiller l'objet plus tard, il suffit d'appeler TryEnter et de le déverrouiller immédiatement s'il est verrouillé.

0
David Schwartz