2009-06-01 6 views
10

Je souhaite incrémenter un entier non signé à partir de plusieurs threads.Incrément non signé C# multi-threadé

Je connais Interlocked.Increment, mais il ne gère pas les entiers non signés. Je pourrais utiliser lock(), mais je ne le ferais pas si possible pour des raisons de performances.

Est-ce que le thread est sûr juste pour l'incrémenter normalement? Peu importe si l'incrément occasionnel a été perdu, car il n'est utilisé que pour les statistiques. Ce que je ne veux pas, c'est la valeur d'être corrompu.

Répondre

-11

vous pouvez déclarer l'uint comme volatile.

http://msdn.microsoft.com/en-us/library/x13ttww7(VS.71).aspx

+7

Cela permet de s'assurer que tout changement apporté à la v ariable sont immédiatement réinscrits dans la mémoire, au lieu d'attendre que le thread produise ou que la valeur soit déplacée dans un registre. Il ne protège pas l'accès au champ, c'est-à-dire que deux (ou plus) threads peuvent lire la même valeur, incrémenter une fois, et réécrire, augmentant ainsi la valeur de 1. –

+0

Veuillez lire les exigences ci-dessus ainsi que l'exemple au http: //msdn.microsoft.com/en-us/library/7a2f3ay4.aspx. Pour le cas donné, cela suffit. – Sesh

+0

Quel est le niveau de performance par rapport à Interlocked.Increment? Même? Meilleur? – jrista

9

Si vous avez vraiment besoin de la gamme complète d'un unsigned int (2^32-1) au lieu d'un int signé (2^31 -1), vous pourriez lancer un int64 (il y a un Interlocked.Increment surcharge qui prend int64), puis renvoyé vers un int non signé.

+0

Ce serait mon choix aussi. – ChrisBD

+3

Notez cependant que Interlocked.Increment (ref long) est seulement réellement atomique sous un système d'exploitation 64-bit (voir la documentation) – jerryjvl

+2

Personnellement, je ferais avec l'int normal pour la sécurité générale ... si 31 bits ne suffit pas, alors Je doute 32 fonctionnera beaucoup mieux, à moins que le problème est spécifiquement restreint exactement entre les mesures 2G et 4G. – jerryjvl

30

Vous dites que vous ne voulez pas utiliser lock pour des raisons de performances - mais l'avez-vous testé? Un verrou incontesté (ce qui est susceptible d'être, par les sons de celui-ci) est assez bon marché.

Je préfère généralement "évidemment correct" plutôt que "intelligent et peut-être plus performant" quand il s'agit de filetage (et en général, mais surtout pour le filetage). Benchmark votre application avec et sans verrouillage, et voir si vous pouvez même remarquer la différence. Si le verrouillage fait différence significative puis sûr, utilisez des trucs astucieux. Sinon, je resterais avec un verrou.

Une chose que vous pourriez vouloir faire est d'utiliser Interlocked.Increment avec un int et juste jeter lorsqu'il est nécessaire d'obtenir un uint, comme ceci:

using System; 
using System.Reflection; 
using System.Threading; 

public class Test 
{ 
    private static int count = int.MaxValue-1; 

    public static uint IncrementCount() 
    { 
     int newValue = Interlocked.Increment(ref count); 
     return (uint) newValue; 
    } 

    public static void Main() 
    { 
     Console.WriteLine(IncrementCount()); 
     Console.WriteLine(IncrementCount()); 
     Console.WriteLine(IncrementCount()); 
    } 

} 

Sortie:

2147483647 
2147483648 
2147483649 

(En d'autres termes, il s'enroule sans aucun problème.)

+1

Je suis d'accord pourquoi compliquer les choses à moins que la performance ne devienne un problème. Je ne peux pas imaginer un verrou pour incrémenter une seule valeur va rester très longtemps ou utiliser beaucoup de ressources. – PeteT

+0

+1 pour un résumé sécurisé! – Galilyou

Questions connexes