锁定语句似乎不起作用

时间:2011-12-25 21:59:46

标签: c# multithreading locking

我有这个方法:

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上抛出异常(Sequence不包含任何元素)。在调试代码时,我看到在另一个线程检查了缓存是否存在之后,正在创建一个从数据库中删除项目的情况。除非lock语句中有多个线程,否则这是不可能的(syncroot对象绝对是跨线程的相同实例)。

不可能?我有证据: Impossible situation

lock语句中有三个线程!是什么给了什么?

注释:

  1. 设置了MRE(不阻塞)。
  2. 这不是抛出异常的情况,它只是在锁定部分内显示多个线程。 更新:我将图片更改为异常的intellitrace事件。旧图片为here
  3. syncroot对象不是静态的,因为我只想调用同步实例同步。
  4. 更新

    这是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)不用于同步 - 它是在执行某些操作(即启动时)后阻止数据库操作一段时间的。它大部分时间都是设置的。将其从锁定块中取出也无法解决问题。

4 个答案:

答案 0 :(得分:3)

我唯一的解释是waitForContextMRE.Wait();调用这个让线程解锁syncroot!所以其他线程可以进入锁定部分。尝试移动waitForContextMRE.Wait();在锁定之前(...)。

答案 1 :(得分:3)

我认为你在调用不同的对象。您的屏幕截图中没有任何迹象表明您正在从不同的线程中获取值。 使用非静态同步根也不是一个好主意,因为可能会导致像你这样的情况。你有充分的理由不让它静止吗?

答案 2 :(得分:0)

我建议锁定TableProperty或DataContext

答案 3 :(得分:0)

我已经调试了这个问题一段时间了,虽然我还没解决,但我很清楚锁正在工作。我猜测问题出在DataContext上(因为在多线程情况下它很棘手)。