2009-05-28 10 views
7

Estoy escribiendo una estructura de datos especial que estará disponible en una biblioteca .NET y una de las características de esta estructura de datos es que será segura para hilos, siempre que solo un hilo le escriba datos, y solo un hilo lo lea datos del mismo (el hilo del lector y el hilo del escritor pueden ser diferentes).Cómo detectar el acceso de subprocesos cruzados en .NET (aplicar la afinidad de subprocesos)?

La pregunta es ¿cómo puedo exigir que todas las operaciones de lectura se ejecuten con el mismo hilo?

Mi solución sería capturar el System.Threading.Thread.ManagedThreadID y almacenarlo en un miembro privado en la primera lectura. Luego, en lecturas posteriores, compruebe el ManagedThreadID contra el guardado y si son diferentes para arrojar una excepción.

¿Eso es suficiente o hay un mecanismo diferente más confiable para hacer esto?

Nota: No es un requisito que esta biblioteca sea utilizable sin un contexto Windows.Forms ..

Respuesta

6

Cuando me encuentro con esta situación utilizo una clase que escribí llamada ThreadAffinity. Todo el propósito es registrar el hilo actual y lanzar accesos no válidos desde un hilo diferente. Tienes que hacer el cheque manualmente, pero encapsula la pequeña cantidad de trabajo para ti.

class Foo { 
    ThreadAffinity affinity = new ThreadAffinity(); 

    public string SomeProperty { 
    get { affinity.Check(); return "Somevalue"; } 
    } 
} 

Clase

[Immutable] 
public sealed class ThreadAffinity 
{ 
    private readonly int m_threadId; 

    public ThreadAffinity() 
    { 
     m_threadId = Thread.CurrentThread.ManagedThreadId; 
    } 

    public void Check() 
    { 
     if (Thread.CurrentThread.ManagedThreadId != m_threadId) 
     { 
      var msg = String.Format(
       "Call to class with affinity to thread {0} detected from thread {1}.", 
       m_threadId, 
       Thread.CurrentThread.ManagedThreadId); 
      throw new InvalidOperationException(msg); 
     } 
    } 
} 

Blog post sobre el tema:

+0

Gracias Jared. Es curioso, ¿ves alguna razón para que @ sixlettervariables responda mejor/peor? –

+1

@Miky D, la única razón por la que diría que es peor es porque está mezclando responsabilidades. Tener una clase separada para verificar el acceso a hilos cruzados no válidos proporciona una experiencia consistente y reutilizable. Sin embargo, es una cantidad muy pequeña de código y lo único que realmente puede estropear es el mensaje de error, así que en mi humilde opinión no es un gran problema. – JaredPar

+0

Estoy de acuerdo con JaredPar en cuanto al uso de una clase, pero no con el uso de la ID Administrada. Pero sí, +1 usa otra clase para manejar la lógica. – user7116

1

Podría no requiere la lectura y escritura de métodos toman un ID de hilo o hilo? Luego puede comparar con el que lo llamó primero, y si no coincide, lanzar una excepción o devolver un código de error, o ignorar la solicitud.

De lo contrario, lo que propone debe funcionar también. Solo necesita comparar los identificadores de subprocesos.

+0

no me gustaría que confiar en lo que la persona que llama de los métodos de lectura/escritura proporciona como entrada. De lo contrario, si puedo usar confiablemente el método ManagedThreadID, supongo que lo usaré. Gracias. –

1

En lugar de comparar ID de hilo, debe almacenar el ambient Thread en su clase durante la construcción.

class SingleThreadedClass 
{ 
    private Thread ownerThread; 

    public SingleThreadedClass() 
    { 
     this.ownerThread = Thread.CurrentThread; 
    } 

    public void Read(...) 
    { 
     if (Thread.CurrentThread != this.ownerThread) 
      throw new InvalidOperationException(); 
    } 

    public void TakeOwnership() 
    { 
     this.ownerThread = Thread.CurrentThread; 
    } 
} 
+0

¿Hay alguna razón específica por la que deba usar una referencia al hilo en lugar de la identificación del hilo? Su técnica es muy similar a la mía, excepto que utiliza referencias a hilos en lugar de ID. Solo curiosidad ... –

+0

Me preocupa la situación en la que una identificación de subprocesos administrada se recicla (¿improbable?). También puede hacer más con el subproceso que con el ID administrado. – user7116

Cuestiones relacionadas