Pregunta

Tengo un C# clase singleton que varias clases de uso.Es el acceso a través de Instance a la Toggle() método thread-safe?Si sí, por lo que los supuestos, las normas, etc.Si no, ¿por qué y ¿cómo puedo solucionarlo?

public class MyClass
{
    private static readonly MyClass instance = new MyClass();

    public static MyClass Instance
    {
        get { return instance; }
    }

    private int value = 0;

    public int Toggle()
    {
        if(value == 0) 
        {
            value = 1; 
        }
        else if(value == 1) 
        { 
            value = 0; 
        }

        return value;
    }
}
¿Fue útil?

Solución

El acceso es a través de la 'Instancia' a la 'Toggle () de la clase de los subprocesos?Si sí, por lo que los supuestos, las normas, etc.Si no, ¿por qué y cómo puedo solucionarlo?

No, no es seguro para subprocesos.

Básicamente, los dos hilos se puede ejecutar el Toggle función en el mismo tiempo, por lo que esto podría suceder

    // thread 1 is running this code
    if(value == 0) 
    {
        value = 1; 
        // RIGHT NOW, thread 2 steps in.
        // It sees value as 1, so runs the other branch, and changes it to 0
        // This causes your method to return 0 even though you actually want 1
    }
    else if(value == 1) 
    { 
        value = 0; 
    }
    return value;

Usted necesita para operar con el siguiente supuesto.

Si 2 hilos se están ejecutando, se puede y se entrelazan e interactúan una con otra de forma aleatoria en cualquier momento.Puede ser la mitad del camino a través de la escritura o la lectura de un entero de 64 bits o float (en una de 32 bits de la CPU) y otro hilo puede saltar y cambiar la parte de debajo de usted.

Si los 2 hilos que no tengan acceso a nada en común, no importa, pero tan pronto como ellos lo hacen, usted necesita para evitar que ingrese en cada uno de los demás dedos de los pies.La forma de hacerlo en .NET es con cerraduras.

Usted puede decidir qué y dónde bloqueo por pensar en cosas como esta:

Para un determinado bloque de código, si el valor de something se cambió la parte de debajo de mí, ¿importa?Si, se necesita de bloqueo que something para la duración de la código de la que sería la materia.

Mirando el ejemplo de nuevo

    // we read value here
    if(value == 0) 
    {
        value = 1; 
    }
    else if(value == 1) 
    { 
        value = 0; 
    }
    // and we return it here
    return value;

Para que esta a devolver lo que nos espera, suponemos que value no se cambia entre la lectura y la return.Para que esta supuesto a ser realmente correcto, usted necesita para bloquear value por la duración de ese bloque de código.

Así que se podría hacer esto:

lock( value )
{
     if(value == 0) 
     ... // all your code here
     return value;
}

Sin EMBARGO

En .NET sólo puede bloquear los Tipos de Referencia.Int32 es un Tipo de Valor, por lo que no puede bloquear.
Podemos solucionar esto mediante la introducción de un 'dummy' objeto, y el bloqueo de que dondequiera que nos gustaría lock 'valor'.

Esto es lo que Ben Scheirman se está refiriendo.

Otros consejos

El original impplementation no es seguro para subprocesos, como señala Ben

Una manera simple de hacerlo hilo seguro es introducir una instrucción de bloqueo.Por ejemplo.como este:

public class MyClass
{
    private Object thisLock = new Object();
    private static readonly MyClass instance = new MyClass();
    public static MyClass Instance
    {
        get { return instance; }
    }
    private Int32 value = 0;
    public Int32 Toggle()
    {
        lock(thisLock)
        {
            if(value == 0) 
            {
                value = 1; 
            }
            else if(value == 1) 
            { 
                value = 0; 
            }
            return value;
        }
    }
}

Que es lo que yo pensaba.Pero, yo estoy buscando los detalles...'Toggle()' no es un método estático, sino que es un miembro de una propiedad estática (cuando el uso de 'Instancia').Es que lo que hace es compartida entre los hilos?

Si la aplicación es multi-hilo y se puede prever que los múltiples hilo tendrá acceso a ese método, que hace que sea compartida entre los hilos.Porque la clase es un Singleton usted sabe que los diferentes hilo tendrán acceso al MISMO objeto, por lo que se advirtió sobre el hilo de seguridad de sus métodos.

Y ¿cómo se aplica esto a los únicos en general.Tengo a la dirección esta en cada método en mi clase?

Como he dicho anteriormente, debido a que es un singleton se conocen diferentes tipos de hilo acceso al mismo objeto, posiblemente al mismo tiempo.Esto no significa que usted tiene que hacer cada método de obtener un bloqueo.Si usted nota que un simultaneos la invocación puede conducir a estado corrupto de la clase, entonces usted debe aplicar el método mencionado por @Thomas

Puedo asumir que el patrón singleton expone mi de otra manera encantadora thread-safe clase para todo el hilo de los problemas de regular los miembros estáticos?

No.Su clase es simplemente no es seguro para subprocesos.El singleton tiene nada que ver con ella.

(Me estoy poniendo mi cabeza en torno al hecho de que los miembros de la instancia llamada a un objeto estático con la causa de roscado de problemas)

No tiene nada que ver con eso.

Tienes que pensar como este:Es posible que en mi programa, por 2 (o más) de los subprocesos para acceder a este pedazo de datos al mismo tiempo?

El hecho de que se puede obtener los datos a través de un singleton, o variable estática, o al pasar un objeto como un parámetro de método no importa.Al final del día es solo algunos de los bits y bytes en tu PC RAM, y todo lo que importa es si varios hilos pueden ver los mismos bits.

El hilo podría parar en el medio de ese método y transferir el control a un subproceso diferente.Usted necesita una sección crítica en torno a que el código de...

private static object _lockDummy = new object();


...

lock(_lockDummy)
{
   //do stuff
}

También me gustaría añadir un constructor protegido a MyClass para evitar que el compilador genere un constructor público predeterminado.

Estaba pensando que si pongo el patrón singleton y fuerza a todos para obtener una nueva instancia de la clase, se podría aliviar algunos problemas...pero eso no detiene a nadie de inicializar un objeto estático de ese tipo y que pasa a su alrededor...o la de cisión de múltiples hilos, todos tienen acceso 'Toggle()' de la misma instancia.

Bingo :-)

Lo tengo ahora.El mundo es difícil.Ojalá no refactorización de código de la herencia :(

Por desgracia, el multithreading es duro y tienes que ser muy paranoico acerca de las cosas :-) La solución más sencilla en este caso es seguir con el singleton, y agregar un bloqueo en el valor, como en los ejemplos.

Bueno, en realidad yo no sé C# que bien...pero estoy bien en Java, así que voy a dar la respuesta para eso, y esperemos que los dos son lo suficientemente similares como para que sea útil.Si no, pido disculpas.

La respuesta es, no, no es seguro.Un hilo se podría llamar Toggle (), al mismo tiempo que los otros, y es posible, aunque raro con este código, que Thread1 podría establecer value en medio de los tiempos que Thread2 cheques y cuando se establece.

Para solucionarlo, simplemente haga Toggle() synchronized.No cuadra en nada o llame a cualquier cosa que pueda generar otro hilo que podríamos llamar Toggle(), por lo que es todo lo que tienes que hacer es guardar.

Cita:

if(value == 0) { value = 1; }
if(value == 1) { value = 0; }
return value;

value siempre será 0...

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top