Condizioni di gara che consentono più transazioni; il blocco degli oggetti in un dizionario può causare problemi?

4

Abbiamo un'API Web MVC chiamata per scrivere transazioni per un importo specifico, in cui l'importo viene addebitato o accreditato sul saldo di un utente. Questo registra il saldo pre-transazione (PreAmount), l'importo e il saldo post-transazione (PostAmount). Abbiamo notato da una semplice query che utilizzava le funzioni LAG e LEAD di SQL Server che vi erano istanze di transazioni aggiunte dall'API che venivano inserite troppo velocemente (parzialmente a causa della mancanza di risorse per l'acquisto di un buon hardware per il server e IIS e SQL in esecuzione nella stessa casella). Abbiamo un meccanismo per impedire l'inserimento della transazione se esiste, ma sembra che la chiamata al metodo venga chiamata molto rapidamente, il che comporta che il record venga aggiunto più volte a causa di una condizione di competizione.

Il modo in cui tenterò di risolvere questo problema è utilizzando Dictionary<long, object> . Il presupposto è che vogliamo che le transazioni per un cliente vengano immesse in sequenza in qualsiasi momento, ma non voglio bloccare richieste concorrenti per più clienti . Il dizionario dovrebbe contenere un numero ID cliente e il valore sarebbe un oggetto che posso bloccare. Quando una transazione sta per essere immessa, controllerò per vedere se c'è un numero ID cliente, e in caso contrario, inseriscilo lì):

private static Dictionary<long, object> customerLocker = new Dictionary<long, object>();
private static object dictLocker = new object();

Quindi, quando viene richiesta una richiesta di verifica di un saldo, o per inserire una transazione, vorrei quindi bloccare quell'oggetto ed eseguire il lavoro necessario:

lock (dictLocker)
{
    if (!customerLocker.ContainsKey(customerID))
        customerLocker.Add(customerID, new object());
}
lock (customerLocker[customerID])
{
    // ... do the work needed for this customer
}

Questa è una buona soluzione al problema che sto avendo? Il blocco degli elementi all'interno di un dizionario causerà problemi? Ci proverò, ma mentre lo sto mettendo insieme, mi piacerebbe vedere l'input degli altri su questo scenario.

    
posta Derreck Dean 02.12.2016 - 20:22
fonte

1 risposta

5

Non è sicuro che tu stia cercando nel dizionario al di fuori di lock , perché così facendo un altro dizionario potrebbe scriverci allo stesso tempo, quindi la tua lettura potrebbe finire per essere corrotta. Devi recuperare il valore per la chiave all'interno di lock .

In alternativa, puoi utilizzare solo ConcurrentDictionary per archiviare gli oggetti per ciascun cliente invece di bloccare l'accesso a Dictionary . Questo ti permetterebbe di scrivere:

private static ConcurrentDictionary<long, object> customerLocker = 
    new ConcurrentDictionary<long, object>();
lock (customerLocker.GetOrAdd(customerID, () => new object()))
{
    // ... do the work needed for this customer
}
    
risposta data 02.12.2016 - 20:26
fonte

Leggi altre domande sui tag