我有这个方法:

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;
    }
}

我从多个线程(调用同一个实例)调用它,但TableProperty.Single(序列不包含任何元素)上不断抛出异常。在调试代码时,我看到正在创建一个情况,在该项目在不同线程检查缓存存在之后,从数据库中删除该项。除非lock语句中有多个线程(syncroot对象绝对是跨线程的同一个实例),否则这是不可能的。
不可能的?我有证据:
lock语句中有三个线程!给什么?
笔记:
已设置MRE(未阻塞)。
这不是抛出异常的情况,它只是在一个锁段中显示多个线程。更新:我将图像更改为异常的IntelliTrace事件。旧图像here
syncroot对象不是静态的,因为我只想同步对同一实例的调用。
更新
这是syncroot对象的声明:
private object syncroot = new object();

以及其他一些声明:
private ManualResetEventSlim waitForContextMRE = new ManualResetEventSlim(true);
private DataContextType _dataContext;
private System.Data.Linq.Table<EntityType> _tableProperty;
//DataContextType and EntityType are generic type parameters

我不能使syncroot成为静态的,因为我有几个类的实例在运行,重要的是它们不要相互阻塞。但这其实并不重要——让它静态化并不能解决问题。
manualresetevent(waitforcontextmre)不用于同步-它用于在执行某些操作(即启动时)之后的特定时间内阻止数据库操作。大部分时间都是这样。把它从锁块中取出也不能解决问题。

最佳答案

我唯一的解释是waitForContextMRE.wait();调用此函数会使线程取消阻止syncroot!所以其他线程可以进入锁段。尝试移动waitForContextMRE.wait();在锁定之前(…)。

08-07 04:13