Come trovare una buona via di mezzo per rendere questa libreria sicura per le operazioni simultanee

1

Ho creato una piccola libreria denominata SignalR.EventAggregatorProxy

Prima di inserirlo nello stato 1.0, devo correggerlo in modo che funzioni in sicurezza con operazioni simultanee. Il modo più semplice è bloccare tutte le operazioni, ma questo è un enorme impatto sulle prestazioni.

La libreria mette in coda le sottoscrizioni degli eventi e quando arriva un evento controlla le sottoscrizioni e aggiorna i client utilizzando SignalR

Questa è la classe che contiene gli abbonamenti

Ci sono 3 metodi che scrivono / leggono alla / e collezione / e di sottoscrizione (io aggrego la sottoscrizione sia a livello di client che a livello di eventi, quindi le sue due raccolte)

  • Iscriviti
  • UnsubscribeConnection
  • Cancella

E quello che legge

  • Maniglia

Comprendo che questa è una libreria, non posso renderla ottimale per tutti gli utenti della libreria, ma come faccio a trovare una buona via di mezzo che non usi i blocchi?

Penso che il metodo Handle sia il metodo più importante e debba avere la priorità per le prestazioni rispetto agli altri 3.

Ho fatto questo piccolo Unittest per testare l'errore di concomitanza

Aggiornamento: Ho scelto di avere scritture bloccate e letture sbloccate. Le scritture non hanno modificato lo stato esistente ma sovrascrivono completamente la raccolta.

    
posta Anders 12.08.2013 - 09:49
fonte

2 risposte

1

Non puoi scappare dall'usare i lucchetti. È necessario assicurarsi che le chiamate al metodo Subscribe imposti sempre lo stato interno con il nuovo sottoscrittore, pertanto è necessario presumere che qualcuno chiamerà il metodo di sottoscrizione in 2 thread esattamente nello stesso momento. L'ultima cosa che vuoi è che 1 thread abbia successo e aggiungi il nuovo subscriber, solo per il 2 ° thread per entrare e impostare il suo subscriber solo per calpestare la voce del primo iscritto nella collezione interna. Scoprire che un bug sarebbe un incubo dato che il rapporto utente sarà "Mi sono iscritto e non è successo niente" o peggio "Mi sono iscritto, è tornato successo ma non ho ricevuto alcun abbonamento".

È possibile che il metodo Handle non debba essere bloccato, purché si possa essere sicuri che qualcuno rimuovendo o aggiungendo un nuovo sottoscrittore non cancelli lo stato della raccolta interna (ovvero un'implementazione ingenua si sovrappone a tutte abbonamenti ... ma cosa succede se il prossimo ciclo arriva attraverso una voce che è stata appena rimossa? La risposta di solito è un crash, ma a volte indefinito, anche in un sistema GC dove l'oggetto rimosso non è ancora stato raccolto, sarà uno giorno, di solito solo quando viene utilizzato in una demo e poi si arresta il crash :-)).

Quindi per evitare i blocchi ... potresti fare una copia della collezione interna di abbonati e usarla nel metodo Handle senza bloccare, quindi hai 2 raccolte - una di tutte le sottoscrizioni e una di sottotitoli 'attivi'. Puoi quindi bloccare il metodo Gestisci e scambiarli quando i nuovi membri vengono aggiunti o rimossi nel metodo Gestisci, in quanto sarai l'unico a chiamare quel metodo per inviare agli iscritti.

Oppure puoi estendere questo per aggiungere nuovi abbonati a una raccolta diversa e unirli in modo sicuro nel metodo Handle, ma dovrai comunque tener conto del caso in cui 2 nuovi sottotitoli vengono aggiunti simultaneamente.

    
risposta data 12.08.2013 - 10:31
fonte
0

Non farlo.

Non è una classe statica e non sono metodi statici, quindi non c'è motivo per cui non dovrebbe essere il massimo per chiamare il codice per evitare chiamate simultanee.

Con i metodi statici, allora dovresti fare un po 'di lavoro per farlo gestire chiamate concorrenti perché il codice di chiamata non può garantire che sia l'unico codice di chiamata.

Ovviamente con i metodi di istanza specificamente orientati alla sincronizzazione dell'accesso ai dati o altrimenti dove essere colpiti simultaneamente da più thread è parte del suo significato, quindi ovviamente devi essere in grado di avere quell'uso simultaneo.

Altrimenti, sei solo nel modo. Stai intralciando l'utente che sa di aver colpito solo i metodi uno alla volta e quindi non ha bisogno di alcun blocco. Stai intralciando l'utente che sa di aver colpito i metodi con più thread e quindi ha codificato una strategia di gestione della concorrenza adatta al loro utilizzo. E al momento della scrittura sei veramente come qualcuno che blocca l'oggetto EventProxy stesso perché stai usando lock(this) così stai bloccando su un oggetto lo scrittore di il codice chiamante dovrebbe essere in grado di pensare a "loro".

    
risposta data 01.04.2015 - 19:04
fonte

Leggi altre domande sui tag