Comment facile de faire ce compteur de propriété thread-safe?
J'ai bien de la définition dans la classe où je n'ai que des Compteurs, ce doit être thread-safe et ce n'est pas parce que get
et set
n'est pas dans la même serrure, Comment faire?
private int _DoneCounter;
public int DoneCounter
{
get
{
return _DoneCounter;
}
set
{
lock (sync)
{
_DoneCounter = value;
}
}
}
Connexes: stackoverflow.com/questions/505515/...
u peut utiliser Contrefil incrément. qui devrait être facile.
si vous demander à propos de "contre", le type de propriété (voir Sean U de réponse), il peut être une bonne idée de mettre à jour "ce" au titre de "contre".
En quoi est-ce pas thread-safe? Qu'essayez-vous de réaliser?
u peut utiliser Contrefil incrément. qui devrait être facile.
si vous demander à propos de "contre", le type de propriété (voir Sean U de réponse), il peut être une bonne idée de mettre à jour "ce" au titre de "contre".
En quoi est-ce pas thread-safe? Qu'essayez-vous de réaliser?
OriginalL'auteur Svisstack | 2012-01-25
Vous devez vous connecter pour publier un commentaire.
Si vous êtes à la recherche pour mettre en œuvre la propriété de telle manière que
DoneCounter = DoneCounter + 1
est la garantie de ne pas être soumis à des conditions de course, il ne peut pas être fait dans la mise en œuvre. Cette opération n'est pas atomique, il en fait trois étapes distinctes:DoneCounter
.DoneCounter
.Vous avez pour se prémunir contre la possibilité qu'un changement de contexte pourrait se produire entre l'un quelconque de ces étapes. De verrouillage à l'intérieur de la getter ou un setter ne va pas aider, parce que le verrouillage du champ d'application existe entièrement à l'intérieur de l'une des étapes (1 ou 3). Si vous voulez vous assurer que toutes les trois étapes se produisent ensemble sans être interrompu, votre synchronisation doit couvrir l'ensemble des trois étapes. Ce qui signifie qu'il a de se produire dans un contexte qui contient toutes les trois d'entre eux. C'est probablement à la fin du code qui n'appartiennent pas à quelle classe contient les
DoneCounter
propriété.Il est de la responsabilité de la personne à l'aide de votre objet à prendre soin de la sécurité des threads. En général, aucune classe de lecture/écriture de propriétés ou de champs peuvent être "thread-safe" de cette manière. Toutefois, si vous pouvez changer la classe de l'interface de sorte que les poseurs ne sont pas nécessaires, alors il est possible de le rendre plus "thread-safe". Par exemple, si vous savez que DoneCounter seulement incréments et décréments, alors vous pourriez re-mettre en œuvre comme suit:
Ensuite, vous pouvez utiliser Interloqué.Ajouter() à la place.
Ce code ne garantie que l'appel
IncrementDoneCounter()
deux fois toujours d'incrémenter le compteur exactement deux fois, ce qui est probablement ce que l'OP voulait. Cependant, pour ceux qui sont à venir dans ce code de vouloir rester à l' distinct nombre de valeurs (par exemple, pour les Identifiants uniques), les utilisateurs de ce code vous devez le modifier pour utiliser la valeur de retour de l'appel àInterlocked.Increment
.Bon point, @Brian. J'ai édité l'exemple en conséquence.
OriginalL'auteur Sean U
À l'aide de la Interloqué classe fournit pour les opérations atomiques, c'est à dire intrinsèquement des threads comme dans ce LinqPad exemple:
+=
n'est pas atomique. Je vous conseille d'utiliserInterlocked.Add
plutôt que+=
dans ce cas. Par ailleurs, l'obtention de réglage/un Int32 est atomique (voir stackoverflow.com/a/11745604/18192), donc je ne suis pas sûr de ce code tente d'accomplir.Voir aussi la démonstration de cette condition de concurrence dans le dotnetfiddle.net/TmHvku. Notez que dotnetfiddle tend à éviter les conditions de course (probablement il n'a pas d'interrupteur de fils très fréquemment), de sorte que vous pourriez ne pas être en mesure de produire des résultats incorrects, à moins que vous tester localement.
OriginalL'auteur David Clarke
Si vous attendez pas juste que certains sujets seront occasionnellement d'écrire pour le compteur en même temps, mais que beaucoup de threads sera de continuer à faire de la sorte, alors vous voulez avoir plusieurs compteurs, au moins un cache-ligne les uns des autres, et ont des threads différents écrire à différents compteurs, résumant quand vous avez besoin de pointage.
Ce qui maintient la plupart des fils des uns et des autres moyens, ce qui les empêche de rinçage des uns et des autres valeurs de la carottes de, et de ralentir les uns les autres. (Vous avez encore besoin de contrefil sauf si vous pouvez garantir que chaque thread va rester séparés).
Pour la grande majorité des cas, vous avez juste besoin de s'assurer occasionnellement un peu de discorde ne pas gâcher les valeurs, dans ce cas Sean U de réponse est meilleur en tout (rayé les compteurs de ce genre sont plus lents non utilisation).
OriginalL'auteur Jon Hanna
Exactement ce que vous essayez de faire avec les compteurs? Les verrous ne sont pas vraiment faire grand chose avec entier propriétés, étant donné que les lectures et les écritures des nombres entiers sont atomiques, avec ou sans verrouillage. Le seul avantage, on peut obtenir à partir de serrures est l'ajout de barrières de mémoire; on peut obtenir le même effet en utilisant des
Threading.Thread.MemoryBarrier()
avant et après à vous de lire ou d'écrire une variable partagée.Je soupçonne votre vrai problème, c'est que vous essayez de faire quelque chose comme "DoneCounter+=1", qui, même avec dispositif de verrouillage-serait d'effectuer la séquence d'événements suivante:
N'est pas très utile, puisque la valeur peut changer entre le get et set. Ce qui serait nécessaire serait une méthode qui permettrait d'effectuer l'obtenir, le calcul, et ensemble, sans aucune intervention de l'exploitation. Il y a trois façons cela peut être accompli:
Threading.Interlocked.Increment
pour ajouter une valeur à _CounterThreading.Interlocked.CompareExchange
boucle de mise à jour _CounterÀ l'aide de l'une de ces approches, il est possible de calculer une nouvelle valeur de _Counter basé sur l'ancienne valeur, de telle manière que la valeur écrite est garanti d'être fondé sur la valeur _Counter avait au moment de l'écriture.
OriginalL'auteur supercat
Vous pouvez déclarer le _DoneCounter variable comme "volatile", pour en faire thread-safe. Voir ceci:
http://msdn.microsoft.com/en-us/library/x13ttww7%28v=vs.71%29.aspx
+1, semms de travailler, j'ai réecrit les propriétés de variable publique, mais je ne peux pas vous accepter, car la question est à propos des propriétés, je pense que ce ne sera pas un travail si volaite grandeur sera à l'intérieur de la classe (privé) et sera wapped avec la propriété publique
cela devrait fonctionner: class c { private volatile int _n; public nvaleur {get { return this._n; } set { this._n = valeur; }} }
Cela ne fonctionnera pas.
volatile
n'empêche pas de filetage à partir de l'entrelacement des opérations de lecture et écriture. Il ne les empêche d'utiliser la mémoire cache du processeur ou de registres. C'est pour les situations où les threads sont autorisés à lire ou écrire une valeur, mais jamais les deux. Partout ailleurs, et la seule chose qu'il fait de façon fiable, c'est de faire votre programme de s'exécuter plus lentement.Et interloqué et serrures apporter leurs propres barrières de la mémoire, ce qui signifie que beaucoup (mais pas tous) des cas où ceux-ci sont utilisées en écrivant pour eux, vous n'en avez pas besoin.
OriginalL'auteur