2009-05-28 8 views
7

Sto scrivendo una struttura dati speciale che sarà disponibile in una libreria .NET e una delle caratteristiche di questa struttura dati è che sarà thread-safe, a condizione che solo un thread scriva dati su di esso e che venga letto solo un thread dati da esso (il thread del lettore e il thread dello scrittore possono essere diversi).Come rilevare l'accesso incrociato in .NET (impone l'affinità del thread)?

La domanda è: come posso far rispettare tutte le operazioni di lettura eseguite dallo stesso thread?

La mia soluzione sarebbe acquisire System.Threading.Thread.ManagedThreadID e memorizzarlo in un membro privato al primo Read. Quindi, nelle letture successive per verificare il ManagedThreadID rispetto a quello salvato e se sono differenti per generare un'eccezione.

È sufficiente, oppure esiste un meccanismo diverso più affidabile per farlo.

Nota: V'è un requisito che questa biblioteca sia utilizzabile senza un contesto Windows.Forms ..

risposta

6

Quando mi imbatto in questa situazione, utilizzo una classe che ho scritto chiamata ThreadAffinity. Il suo scopo è quello di registrare il thread corrente e lanciare accessi non validi da un thread diverso. Devi fare manualmente il controllo ma incapsula la piccola quantità di lavoro per te.

class Foo { 
    ThreadAffinity affinity = new ThreadAffinity(); 

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

Classe

[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 su questo argomento:

+0

Grazie Jared. Solo curioso, vedi qualche ragione @ la risposta di sixlettervariables sarebbe meglio/peggio? –

+1

@Miky D, l'unica ragione per cui direi che è peggio è perché mescola le responsabilità. Avere una classe separata per il controllo di un accesso incrociato non valido fornisce un'esperienza coerente riutilizzabile. È una piccola quantità di codice e l'unica cosa che puoi davvero rovinare è il messaggio di errore, quindi IMHO non è un grosso problema. – JaredPar

+0

Sono d'accordo con JaredPar per quanto riguarda l'utilizzo di una classe, non solo con l'utilizzo dell'ID gestito. Ma sì, +1 usa un'altra classe per gestire la logica. – user7116

1

Potrebbe non richiede la lettura e scrittura metodi di prendere un filo o filo ID? Quindi puoi semplicemente confrontare quello che l'ha chiamato per primo, e se non corrisponde, lanciare un'eccezione o restituire un codice di errore, oppure ignorare la richiesta.

In caso contrario, ciò che si propone dovrebbe funzionare anche. Devi solo confrontare gli ID dei thread.

+0

non vorrei fare affidamento su ciò che il chiamante dei metodi di lettura/scrittura fornisce come input .. Altrimenti, se posso usare in modo affidabile il metodo ManagedThreadID suppongo che lo userò. Grazie. –

1

Invece di confrontare i thread ID, è necessario memorizzare ambient Thread nella classe durante la costruzione.

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

C'è qualche ragione specifica per cui dovrei usare un riferimento al Thread al contrario dell'ID del thread? La tua tecnica è molto simile alla mia, tranne che usa riferimenti a thread anziché ID. Solo curiosità .. –

+0

Mi preoccupo della situazione in cui un ID thread gestito viene riciclato (improbabile?). Puoi anche fare di più con la Discussione rispetto all'ID gestito. – user7116

Problemi correlati