È una buona idea che il comportamento del metodo dipenda dal thread chiamante?

2

Voglio creare una sottoclasse di una classe di terze parti, per renderla protetta da thread.

Ho una buona idea di come implementarlo, ma c'è un problema: la superclasse ha una proprietà, che influenza il comportamento di uno dei suoi metodi. Se un thread imposta la proprietà, interferirà con gli altri thread quando chiamano il metodo.

Posso vedere due modi per farlo:

  1. Crea un oggetto "stateless" thread-safe che quindi contiene più "viste". La proprietà è nella vista e ogni thread ha la propria istanza di visualizzazione.
  2. Rileva quale thread effettua la chiamata nell'accessorio get della proprietà e nel metodo, e memorizza internamente lo stato per quel thread.

(1) è auto-esplicativo, ma coinvolge più codice boilerplate. (2) fa qualcosa di non banale dietro le quinte, ma se funziona, è completamente trasparente.

Quale è il migliore, per manutenibilità e leggibilità? Il codice più complesso, ma il cui comportamento è immediato, o il codice che è più facile da usare quando funziona, ma se si rompe lo farà in una posizione e in un modo che non è ovvio?

C'è qualche ragione per cui un oggetto non deve dipendere da quale thread interagisce con esso?

(EDIT: rimozione del riferimento alla classe di terze parti, poiché i requisiti dell'implementazione non sono così semplici come sembra e generava più confusione del necessario!)

    
posta sebf 26.10.2015 - 20:04
fonte

4 risposte

6

L'idea di avere una variabile specifica del thread non è irragionevole, anche se non sono sicuro se sia appropriato per il tuo caso d'uso. L'idea di Stream sicuro per i thread mi sembra un po 'spezzata; Preferirei avere un% diStreamFactory sicuro per i thread.

Il modo migliore per implementare una variabile di stato specifica del thread è utilizzare ThreadStatic o ThreadLocal<T> . Questo rende il tuo codice breve, semplice e banalmente gestibile. Questa variabile sarà un membro del tuo Stream .

Vedi ThreadStatic v.s. ThreadLocal: è generico meglio dell'attributo? per la discussione su quale usare (versione breve: usa ThreadLocal<T> se sei su .Net 4 +).

    
risposta data 26.10.2015 - 20:55
fonte
7

Questo non risponde alla tua domanda, ma:

  1. Non è una buona idea creare una sottoclasse di una classe di terze parti, in modo da renderla sicura per i thread . Molto probabilmente l'autore non ha pensato alla sicurezza del thread durante la progettazione della classe, quindi sarà molto difficile aggiungerlo per sottoclassi, se possibile. Pensare al polimorfismo e alla sicurezza del filo allo stesso tempo è semplicemente troppo. Cosa succede se l'implementazione della classe cambierà?
  2. Non è una buona idea creare uno stream sicuro per i thread . Lo streaming non può essere letto da due lettori allo stesso tempo, quindi perché preoccuparsi di accedervi da più thread? Complessità accidentale .
risposta data 26.10.2015 - 20:58
fonte
2

Interessante. In Delphi puoi dichiarare le variabili come threadvar che assicura che ogni thread abbia la propria copia. Tuttavia, questi sono vars globali e quindi hanno i loro inconvenienti. Quindi un collega ha elaborato dati "thread-stance". Dati che sono sia thread che istanza specifica. Molto simile alla tua opzione 2. Ha funzionato e funziona magnificamente.

Data la scelta oggi, opterei per l'opzione 1.

Mentre l'opzione 2 potrebbe rendere le cose completamente trasparenti per i tuoi colleghi sviluppatori, non penso che sia necessariamente una buona cosa. Viene a costo di oscurare la natura "thread-dependent" di quella classe. Qualcosa di cui uno sviluppatore dovrebbe sempre essere a conoscenza.

L'opzione 1 rende tutto molto più esplicito, e io, mi piace esplicito.

    
risposta data 26.10.2015 - 21:04
fonte
0

Affermare l'ovvio, la creazione di uno stream sincronizzato è completamente inutile 1 .

Non è che non si possa garantire che gli interni dei vapori non siano stravolti dal multi-threading, che in realtà è davvero facile.
Il problema deriva dal fatto che quasi tutto il codice si basa sull'accesso esclusivo implicito allo stream per garantire che i pezzi concettualmente atomici di output non vengano interrotti arbitrariamente e interrotti l'un l'altro, il che renderà l'output flat-out inutile.

Se più thread possono accedere allo stesso thread, fanno affidamento su di te, il programmatore, sincronizzando sensibilmente l'accesso in unità logiche .

Riguardo alle eccezioni, questo è per le poche volte in cui entrambi assicuri che l'output verrà spostato nello stream in unità logiche (chiunque sia presente a bordo o che tu stia utilizzando un flusso di inoltro che non sarà mai automatico -flush ), o le cose sono così rotte puoi solo scrivere il tuo messaggio di errore, sperare per il meglio e abortire comunque.

    
risposta data 29.10.2015 - 22:32
fonte