59 votes

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

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

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

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

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

et ceci :

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 verrouille un membre privé alors que la seconde approche verrouille l'instance elle-même (elle devrait donc verrouiller tout le reste de l'instance). Y a-t-il un conseil général sur l'approche à utiliser ? J'ai actuellement trouvé deux classes avec un objectif similaire dans notre projet, chacune écrite avec une approche différente.

Editar:

Peut-être une autre question. Est-ce que c'est ça :

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

exactement la même chose que ça :

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

4 votes

0 votes

@Winston : Super. Ma question est presque une copie.

0 votes

Je considérerais la forme de l'attribut comme une "suggestion polie" au compilateur. Je ne suis pas sûr qu'ils soient tenus par la norme de la suivre. Alors que l'utilisation explicite d'un lock impose une exigence au moment de la compilation.

42voto

Henk Holterman Points 153608

La première méthode est préférable parce que vous pouvez (et devriez) faire _syncRoot privé. Cela réduit le risque de blocage.

El MethodImplOptions.Synchronized est un reliquat d'une idée ambitieuse antérieure qui s'est avérée ne pas être si bonne après tout.

Concernant la dernière question : Oui, selon ce blog ils sont fonctionnellement équivalents (mais pas mis en œuvre de la même manière). Et toutes les formes de lock(this) sont déconseillés, toujours en raison des scénarios de blocage.

3 votes

La disponibilité publique entre autres.

1 votes

En effet, le fait que n'importe qui puisse verrouiller est le problème mentionné ici. blogs.msdn.com/b/bclteam/archive/2004/01/20/60719.aspx

0 votes

Qu'en est-il de l'utilisation de "MethodImplOptions.Synchronized" en interne, pour des raisons de sécurité ? private méthodes uniquement ?

12voto

Kamyar Points 11012

Vérifier 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 de lock(this) aussi et déconseille de l'utiliser depuis :

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

Citation de EE :

Si vous verrouillez un objet, tous les autres threads qui doivent accéder à CET OBJET PARTICULIER attendront, jusqu'à ce que l'autre objet ait terminé. En revanche, si vous marquez une méthode comme étant Synchronisée, CETTE MÉTHODE PARTICULIÈRE ne sera pas exécutée par plus d'un thread. Lock sécurise l'objet, Synchronized sécurise la méthode.

0 votes

Oui, je suis au courant de ce problème. Il est directement indiqué dans MSDN que les méthodes synchronisées ne doivent pas être utilisées sur les classes publiques.

2 votes

+1 pour la deuxième citation. C'est la distinction la plus importante entre les deux mécanismes, selon moi.

0 votes

"CETTE MÉTHODE PARTICULIÈRE ne sera pas exécutée à plus d'un fil" GAGNEZ POUR MOI, moins de code, facile, 1 ligne ... magnifique ! juste ce dont j'ai besoin. Si j'ai beaucoup de threads qui tournent en rond, lock() deviendra un enfer.

8voto

Turowicz Points 1120

J'ai jeté un coup d'œil rapide et j'ai constaté que les dispositifs 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 du code autre que le vôtre peut prendre des verrous sur les types et les instances publiques. 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

0 votes

Je connais la description MSDN. Mes classes ne sont pas publiques.

2voto

Steve Mallory Points 2713

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 d'effectuer le verrouillage le plus spécifique possible, si nécessaire.

1voto

Hasanain Points 729

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

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

Hasanain

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X