2009-06-01 8 views
10

Quiero incrementar un entero sin signo a partir de varios hilos.C# Incremento múltiple sin rosca

Sé acerca de Interlocked.Increment, pero no maneja enteros sin signo. Podría usar lock(), pero preferiría no hacerlo si fuera posible por razones de rendimiento.

¿Es seguro para subprocesos simplemente incrementarlo de la manera normal? No importaría si el incremento ocasional se pierde, ya que solo se usa para estadísticas. Lo que no quiero es que el valor se corrompa.

Respuesta

-11

puede declarar el uint como volátil.

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

+7

Eso solo asegura que cualquier cambio en el v ariable se escriben en la memoria de inmediato, en lugar de esperar hasta que el hilo ceda o el valor se desplace en un registro. No protege el acceso al campo, es decir, dos (o más) subprocesos pueden leer el mismo valor, incrementar una vez y escribir de nuevo, aumentando efectivamente el valor en 1. –

+0

Lea los requisitos anteriores y también el ejemplo en http: //msdn.microsoft.com/en-us/library/7a2f3ay4.aspx. Para el caso dado, es suficiente. – Sesh

+0

¿Qué tan eficiente es la volatilidad en comparación con Interlocked.Increment? ¿Mismo? ¿Mejor? – jrista

9

Si realmente necesita la gama completa de un entero sin signo (2^32 - 1) en lugar de un int firmado (2^31 -1), en que pudieras jugar a un Int64 (hay una Interlocked.Increment sobrecarga que toma int64) y luego regresa a un int sin signo.

+0

Esa sería mi elección también. – ChrisBD

+3

Tenga en cuenta que Interlocked.Increment (ref long) solo es atómico en un sistema operativo de 64 bits (ver documentación) – jerryjvl

+2

Personalmente me gustaría tener acceso a la int normal para la seguridad general ... si 31 bits no es suficiente, entonces Dudo que 32 realmente funcione mucho mejor, a menos que el problema esté específicamente restringido exactamente entre mediciones 2G y 4G. – jerryjvl

30

Usted dice que no quiere usar lock por razones de rendimiento, pero ¿lo ha probado? Un bloqueo no disputado (que es probable que sea así, por los sonidos del mismo) es bastante barato.

Generalmente prefiero "obviamente correcto" en lugar de "inteligente y posiblemente mejor rendimiento" cuando se trata de enhebrar (y en general, pero especialmente para enhebrar).

Comparativa de su aplicación con y sin bloqueo, y vea si puede notar la diferencia. Si el bloqueo hace una diferencia significativa de , entonces seguro, use astucia. De lo contrario, me quedaría con un candado.

Una cosa que puede querer hacer es usar Interlocked.Increment con un int y simplemente echarlo cuando sea necesario para obtener una uint, así:

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()); 
    } 

} 

Salida:

2147483647 
2147483648 
2147483649 

(En otras palabras, se envuelve sin problemas.)

+1

Acepto por qué complicar las cosas a menos que el rendimiento realmente se convierta en un problema. No puedo imaginarme que un bloqueo para incrementar un solo valor vaya a permanecer por mucho tiempo o use muchos recursos. – PeteT

+0

+1 para la envoltura segura! – Galilyou