Strategie per gestire o evitare le condizioni di gara

2

Sto lavorando su un'applicazione .NET dove carico il mio DB di lavoro (operazioni di salvataggio) su un thread separato (ispirato da come NodeJS gestisce le operazioni IO). Un'operazione di salvataggio si riduce a questa (utilizzando Entity Framework):

public void Save(Customer customer)
{
    Task.Factory.StartNew(() =>
    {
        using (var entities = new MyEntities())
        {
            var persistedCustomer 
                = entities.Customers.FirstOrDefault(x => x.Number == customer.Number);

            if (persistedCustomer == null)
            {
                persistedCustomer = new DBCustomer();
                // set properties
                entities.Customers.AddObject(persistedCustomer);
            }
            else
            {
                // set properties
            }

            entities.SaveChanges();
        }
    });
}

Quindi, in sostanza:

  • controlla se l'entità esiste già nel DB
  • in caso contrario, creane uno nuovo
  • se già esiste, aggiorna quello esistente

Dove questo a volte si rompe è quando due chiamate al metodo Save vengono eseguite contemporaneamente. Entrambi i thread vedono che l'entità non esiste ancora e vogliono fare un inserto. Una condizione di gara standard.

Come faresti a risolvere questo problema? Qualche esperienza con questo?

Potrei implementare un meccanismo di tentativi, ma mi chiedevo se ci sono altre opzioni. Ovviamente, un semplice tentativo potrebbe sovrascrivere alcune proprietà che il salvataggio precedente aveva aggiornato.

    
posta Peter 17.03.2015 - 10:26
fonte

1 risposta

6

Problemi come questo sono spesso risolti con le code.

Se stai salvando lo stesso cliente, lo inserisci in un ConcurrentQueue<T> . Poi c'è un thread che legge la coda in sequenza e fa leggere l'aggiornamento su ogni elemento. Solo il punto in cui avviene la sincronizzazione tra i thread è in fase di inserimento nella coda e può essere eseguito sia rapidamente che senza il rischio di deadlock.

    
risposta data 17.03.2015 - 11:19
fonte

Leggi altre domande sui tag