web-dev-qa-db-fra.com

Différence entre le verrouillage manuel et les méthodes synchronisées

Y a-t-il une différence entre cela:

internal class MyClass
{
    private readonly object _syncRoot = new Object();

    public void DoSomething() 
    {
        lock(_syncRoot)
        {
            ...
        }
    }

    public void DoSomethingElse() 
    {
        lock(_syncRoot)
        {
            ...
        }
    }
}

et ça:

internal class MyClass
{
    [MethodImpl(MethodImplOptions.Synchronized)]
    public void DoSomething() 
    {
        ...
    }

    [MethodImpl(MethodImplOptions.Synchronized)]
    public void DoSomethingElse() 
    {
        ...
    }
}

La seule différence que je vois est que la première approche se verrouille sur un membre privé alors que la seconde approche se verrouille sur l'instance elle-même (elle devrait donc verrouiller tout le reste dans l'instance). Existe-t-il des conseils généraux sur l'approche à utiliser? J'ai actuellement trouvé deux classes avec un objectif similaire dans notre projet chacune écrite avec une approche différente.

Éditer:

Peut-être encore une question. Est-ce:

internal class MyClass
{
    [MethodImpl(MethodImplOptions.Synchronized)]
    public void DoSomething() 
    {
        ...
    }
}

exactement comme ça:

internal class MyClass
{
    public void DoSomething() 
    {
        lock(this) 
        {
            ...
        }
    }
}
54
Ladislav Mrnka

La première méthode est préférée car vous pouvez (et devez) rendre _syncRoot privé. Cela réduit le risque de blocage.

Le MethodImplOptions.Synchronized Est un reliquat d'une idée ambitieuse antérieure qui s'est révélée pas si bonne après tout.

Concernant la dernière question: Oui, selon ce blog ils sont fonctionnellement équivalents (mais pas implémentés de la même manière). Et toutes les formes de lock(this) sont déconseillées, encore une fois en raison de scénarios de blocage.

38
Henk Holterman

consultez http://blogs.msdn.com/b/bclteam/archive/2004/01/20/60719.aspx et http://www.experts-exchange.com /Programming/Languages/C_Sharp/Q_20926988.html
Ils discutent également de lock(this) et découragent de l'utiliser depuis:

un code complètement indépendant peut également choisir de verrouiller cet objet

Citant EE:

Si vous verrouillez un objet, tous les autres threads qui doivent accéder à CET OBJET PARTICULIER attendront jusqu'à ce que l'autre objet se termine. Cependant, si vous marquez une méthode comme synchronisée, cette méthode particulière ne sera pas exécutée sur plusieurs threads. Lock sécurise l'objet, Synchronized sécurise la méthode.

13
Kamyar

Juste avoir un coup d'œil rapide et constaté que les appareils portables ne prennent pas en charge MethodImplOptions.Synchronized.

Il y a aussi une remarque:

Le verrouillage sur l'instance ou sur le type, comme avec l'indicateur Synchronized, n'est pas recommandé pour les types publics, car un code autre que le vôtre peut prendre des verrous sur les types et les instances publics. Cela peut provoquer des blocages ou d'autres problèmes de synchronisation.

source: http://msdn.Microsoft.com/en-us/library/system.runtime.compilerservices.methodimploptions%28v=VS.100%29.aspx

8
Wojtek Turowicz

Je pense que la différence dépendrait des objets référencés dans les méthodes décorées. D'après ce que j'ai lu, la décoration implémente en fait lock () en IL.

La meilleure approche serait de faire le verrouillage le plus spécifique si nécessaire.

2
Steve Mallory

Cet article peut vous aider: http://www.yoda.arachsys.com/csharp/threads/lockchoice.shtml

En général, j'éviterais de verrouiller "ceci", car les variables de verrouillage privées offrent un meilleur contrôle. Je recommanderais de verrouiller "this", s'il s'agit d'une classe de collection personnalisée, quelque chose dans le sens de SyncRoot, si c'est ce qui est requis.

Hasanain

1
Hasanain