ho questo metodo:istruzione lock non sembra funzionare
public bool Remove(EntityKeyType key)
{
lock (syncroot)
{
//wait if we need to
waitForContextMRE.Wait();
//if the item is not local, assume it is not remote.
if (!localCache.ContainsKey(key)) return false;
//build an expression tree
Expression<Func<EntityType, bool>> keyComparitorExpression = GenerateKeyComparitorExpression(key);
var itemToDelete = TableProperty.Single(keyComparitorExpression);
//delete from db
TableProperty.DeleteOnSubmit(itemToDelete);
DataContext.SubmitChanges();
//get the removed item for OnCollectionChanged
EntityType itemToRemove = localCache[key];
itemToRemove.PropertyChanged -= item_PropertyChanged;
//remove from the list
Debug.Assert(localCache.Remove(key));
//call the notification
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, itemToRemove));
return true;
}
}
sto chiamando da più thread (chiamando lo stesso esempio), ma un'eccezione continua ad essere gettato su TableProperty.Single (Sequenza contiene nessun elemento). Dopo aver eseguito il debug del codice, ho visto che si sta creando una situazione in cui l'elemento viene eliminato dal database dopo che un thread diverso ha verificato la presenza della cache. Questo non dovrebbe essere possibile a meno che non ci siano più thread all'interno dell'istruzione lock (l'oggetto syncroot è sicuramente la stessa istanza tra thread).
Impossibile? Ho la prova:
Ci sono tre thread all'interno dell'istruzione lock! Cosa dà?
note:
- Il MRE è impostata (non il blocco).
- Questa non è una situazione in cui viene generata l'eccezione, mostra solo più thread all'interno di una sezione di blocco. Aggiornamento: Ho modificato l'immagine in un evento Intellitrace dell'eccezione. L'immagine precedente è here
- L'oggetto syncroot non è statico, perché desidero solo le chiamate alla stessa istanza sincronizzate.
Aggiornamento
Questa è la dichiarazione dell'oggetto SyncRoot:
private object syncroot = new object();
Ed alcune altre dichiarazioni:
private ManualResetEventSlim waitForContextMRE = new ManualResetEventSlim(true);
private DataContextType _dataContext;
private System.Data.Linq.Table<EntityType> _tableProperty;
//DataContextType and EntityType are generic type parameters
non posso fare lo SyncRoot statica perché ho diverse istanze della classe in esecuzione ed è importante che non si blocchino k a vicenda. Ma questo non ha molta importanza: renderlo statico non risolve il problema.
ManualResetEvent (waitForContextMRE) non è presente per la sincronizzazione: è lì per bloccare le operazioni del database per un certo periodo di tempo dopo l'esecuzione di determinate operazioni (ad esempio all'avvio). È impostato per la maggior parte del tempo. Toglierlo dal blocco di blocco non risolve il problema.
A: possiamo vedere dove stai inizializzando 'syncroot', e B: per quanto tempo è in gioco il contesto oggetto? C: sei sicuro che siano la stessa istanza? Difficile da dire dallo stato di pausa ... –
Suggerirei di aggiungere messaggi di traccia, con System.Diagnostics.Debug.WriteLine. Scrivi l'id del thread e l'hashcode syncroot all'inizio e alla fine del blocco di blocco. Quindi puoi facilmente vedere nella finestra di output se due thread si sovrappongono allo stesso syncroot, cosa che sicuramente non dovrebbe accadere. –
Qual è il danno nel rendere Syncroot statico? –