2010-06-27 15 views
15

Al leer la documentación de MSDN, siempre le permite saber si una clase es segura para subprocesos o no. Mi pregunta es ¿cómo se diseña una clase para que sea segura? No estoy hablando de llamar a la clase con el bloqueo. Quiero decir que estoy trabajando para Microsoft, creo XXX class \ object y quiero decir que es "Thread Safe" ¿qué debo hacer?Diseño de una clase Thread Safe

+1

Véase p. http://stackoverflow.com/questions/564319/achieving-thread-safety. –

+0

No estoy tratando de PRUEBA para la seguridad del hilo. Estoy preguntando qué debe tener en cuenta para diseñarlo ... – Shane

Respuesta

8

La manera más fácil y más infalible de hacer que un hilo de clase sea seguro es hacerlo immutable. La belleza de esto es que nunca tendrás que molestarte en volver a bloquear.

Receta: Hacer todas las variables de instancia readonly en C# (final en Java).

  • Un objeto inmutable, una vez creado e inicializado en el constructor, no puede cambiar.
  • Un objeto inmutable es seguro para subprocesos. Período.
  • Esto no es lo mismo que tener una clase con solo constantes.
  • Para partes mutables de su sistema, aún necesita tener en cuenta y manejar las propiedades de bloqueo/sincronización. Esta es una de las razones para escribir clases inmutables en primer lugar.

Consulte este question también.

+1

No estoy de acuerdo con usted por 2 razones. 1. Hay diferentes tipos de inmutabilidad con los que trabajamos. http://blogs.msdn.com/b/ericlippert/archive/2007/11/13/immutability-in-c-part-one-kinds-of-immutability.aspx 2.'final 'es Java, usted significa hacerlos constantes? Si es así, no estoy de acuerdo. Hacer todos los campos en las constantes de clase es muy diferente de hacerlos enhebrables. – ram

+1

Ser inmutable es inútil cuando se necesitan hilos para compartir datos (lo que supongo que se basa en la pregunta). – Gabe

+1

Por último, quiero decir _Asegúrate de que tenga un valor después del constructor, y ese valor solo se lea una vez asignado_. Hay muchos ejemplos que prueban mi punto, es decir, http://blogs.msdn.com/b/lucabol/archive/2007/12/06/creating-an-immutable-value-object-in-c-part -ii-making-the-class-better.aspx http://pebblesteps.com/post/Introduction-to-Immutability-in-C.aspx –

4

Para indicar que la clase es segura para subprocesos, está confirmando que las estructuras de datos internas de la clase no se dañarán mediante el acceso simultáneo de varios subprocesos. Para hacer esa afirmación, necesitaría introducir el bloqueo (sincronización en Java) alrededor de las secciones críticas del código dentro de la clase, lo que potencialmente podría conducir a la corrupción de que fueran ejecutadas por múltiples hilos concurrentes.

+0

No necesita introducir el bloqueo necesariamente. Puede hacer algunas cosas bastante sofisticadas con System.Threading.Interlocked. *. – Spence

+0

Otra forma, quizás más fácil, de hacer esa afirmación es marcar todas las variables de instancia 'readonly' para hacer que la clase sea inmutable. –

0

Las clases no genéricas ICollection proporcionan propiedades para la seguridad del hilo. IsSynchronized y SyncRoot. desafortunadamente no puedes configurar IsSynchronized. Puede leer más sobre ellos here

En sus clases puede tener algo similar a IsSynchronized y Syncroot, exponer los métodos/propiedades públicos solo y el método interno de verificación del cuerpo para ellos. Su IsSynchronized será una propiedad de sólo lectura, por lo que una vez que se ha inicializado la instancia, usted no será capaz de modificarlo

bool synchronized = true; 
var collection = new MyCustomCollection(synchronized); 
var results = collection.DoSomething(); 

public class MyCustomCollection 
{ 
    public readonly bool IsSynchronized; 
    public MyCustomCollection(bool synchronized) 
    { 
    IsSynchronized = synchronized 
    } 

    public ICollection DoSomething() 
    { 
    //am wondering if there is a better way to do it without using if/else 
    if(IsSynchronized) 
    { 
    lock(SyncRoot) 
    { 
     MyPrivateMethodToDoSomething(); 
    } 
    } 
    else 
    { 
     MyPrivateMethodToDoSomething(); 
    } 

    } 
} 

Puede leer más acerca de cómo escribir colecciones seguras hilo en Jared Parson's blog

0

La documentación no hace sugieren que las clases son seguras para hilos, solo los métodos lo son. Para afirmar que un método es seguro para subprocesos, tiene que ser invocado desde múltiples subprocesos simultáneamente sin dar resultados incorrectos (donde los resultados incorrectos serían el método devolviendo el valor incorrecto o el objeto entrando en un estado inválido).

Cuando la documentación dice

estáticos públicos (Shared en Visual Basic) de este tipo son el hilo seguro.

probablemente significa que los miembros estáticos de la clase no cambian el estado compartido.

Cuando la documentación dice

los miembros de instancias están garantizados para la ejecución de subprocesos.

probablemente significa que los métodos tienen un bloqueo interno mínimo.

Cuando la documentación dice

Todos los miembros públicos y protegidos de esta clase son hilos de proceso seguro y puede ser utilizado simultáneamente desde múltiples hilos .

probablemente significa que todos los métodos que puede llamar utilizan el bloqueo apropiado dentro de ellos. También es posible que los métodos no muten ningún estado compartido, o que sea una estructura de datos sin bloqueo que el diseño permite el uso simultáneo sin bloqueos.

0

Las clases de seguridad de subprocesos se trata de proteger los datos (variables de instancia) en su clase. La forma más común de hacerlo es usar la palabra clave . El error de novato más común es el uso de bloquear toda la clase en lugar de un bloqueo de más de grano fino:

lock (this) 
{ 
    //do somethnig 
} 

El problema con esto es que se le puede dar un rendimiento importante si la clase hace algo importante. La regla general es bloquear lo menos posible en el menor tiempo posible.

Puede leer más aquí: lock keyword in C#

Cuando haya strarted para entender más profundamente multithreadnig también se puede echar un vistazo a ReaderWriterLoch y semáforo. Pero sugiero que solo comiences con la palabra clave de bloqueo.

5

Además de las otras excelentes respuestas aquí, considere otro ángulo también.

No es suficiente que la estructura de datos interna de la clase sea 100% segura para subprocesos si la API pública tiene operaciones de varios pasos que no se pueden usar de forma segura para subprocesos.

Considere una clase de lista que ha sido construida de tal forma que no importa cuántos hilos estén haciendo sin importar cuántos tipos de operaciones contenga, la estructura de datos interna de la lista siempre será consistente y correcta.

consideran este código:

if (list.Count > 0) 
{ 
    var item = list[0]; 
} 

El problema aquí es que entre la lectura de la propiedad Count y la lectura del primer elemento a través de la [0] indexador, otro hilo podría haber limpiado el contenido de la lista .

Este tipo de seguridad de subprocesos generalmente se olvida cuando se crea la API pública. Aquí, la única solución es que el código de llamada bloquee manualmente algo en cada tipo de acceso para evitar que el código se cuelgue.

Una manera de resolver esto sería para el autor tipo de lista para considerar escenarios de uso típicos y añadir los métodos apropiados para el tipo:

public bool TryGetFirstElement(out T element) 

entonces tendría que:

T element; 
if (list.TryGetFirstElement(out element)) 
{ 
    .... 

presumiblemente , TryGetFirstElement funciona de manera segura para hilos y nunca devolverá true al mismo tiempo, ya que no puede leer el primer valor del elemento.

+1

Vale la pena señalar que en muchos casos es posible que una clase especifique varios tipos de seguridad de hilos.Por ejemplo, sería mucho más barato para una implementación 'IDictionary ' especificar que cualquier instancia en la que 'Delete' nunca se haya llamado será segura para subprocesos con un número arbitrario de lectores y escritores siempre que no haya dos escritores actuando sobre la misma clave al mismo tiempo, y ningún lector solicita una clave cuyo valor asociado se está modificando (pero que existía antes de tal modificación) a menos que 'TValue' sea un tipo de referencia, que prometer seguridad de hilos completos. – supercat