这段代码会导致死锁吗?

时间:2018-04-12 12:54:07

标签: c# locking

我正在回顾一段时间前我写的一段代码,现在我想知道同一个变量上的嵌套锁是否会导致死锁

lock (DealLock)
{
     if (dealmapping.ContainsKey(deal.Deal.Id))
     {
        var oldItem = dealmapping[deal.Deal.Id];

        var index = Deals.FindIndex(x => x.Id == deal.Deal.Id);

        if (index > -1)
            if (deal.Status == DealStatus.Updated)
            {
                  Deals[index].PopulateWith(deal);

                  Deals[index].IsChanged = true;


            }
            else
            {
                  Deals.Remove(Deals.First(x => x.Id == deal.Deal.Id));
            }

            lock (DealLock) //This one
            {
                   dealmapping = Deals.ToDictionary(x => x.Id, y => y);
            }
}

内锁是否无用/不正确,因为我之前只是锁定了?

谢谢你

更新#1

阅读完帖后,展示的解决方案将是

if (dealmapping.ContainsKey(deal.Deal.Id))
{
   var oldItem = dealmapping[deal.Deal.Id];

   var index = Deals.FindIndex(x => x.Id == deal.Deal.Id);

   if (index > -1)
   {
       lock (DealLock)
       {
            if (deal.Status == DealStatus.Updated)
            {
               Deals[index].PopulateWith(deal);

               Deals[index].IsChanged = true;

            }
            else
            {
               Deals.Remove(Deals.First(x => x.Id == deal.Deal.Id));
            }

            dealmapping = Deals.ToDictionary(x => x.Id, y => y);
     }
   }
}

更新2

对不起,我发现了另一段使用锁的代码,我觉得这里有比以前更多的问题

  private object isRefreshingLock = new object();

    public void Refresh()
    {
        if (!IsVisible) return;

        lock (isRefreshingLock)
        {
            dispatcherService.BeginInvoke(() =>
            {
                if (ScrollViewer != null)
                {
                    HorizontalScrollViewOffset = ScrollViewer.HorizontalOffset;
                    VerticalScrollViewOffset = ScrollViewer.VerticalOffset;
                }

                lock (_queueLock)
                {
                    while (queue.Count > 0)
                        try
                        {
                            var deal = queue.Dequeue();

                            Log.Verbose($"Deal base - Dequeued {deal.Deal.Id} from deal queue");
                            if (deal.Status == DealStatus.New && !dealmapping.ContainsKey(deal.Deal.Id))
                            {
                                lock (DealLock)
                                {
                                    Deals.Add(deal.Deal);
                                    dealmapping = Deals.ToDictionary(x => x.Id, y => y);
                                }

                                Log.Verbose($"Deal base - Added {deal.Deal.Id} to deals");
                            }
                            else
                            {
                                lock (DealLock)
                                {
                                    if (dealmapping.ContainsKey(deal.Deal.Id))
                                    {
                                        var oldItem = dealmapping[deal.Deal.Id];

                                        var index = Deals.FindIndex(x => x.Id == deal.Deal.Id);

                                        if (index > -1)
                                            if (deal.Status == DealStatus.Updated)
                                            {
                                                Deals[index].PopulateWith(deal.Deal);

                                                Deals[index].IsChanged = true;

                                                Log.Verbose($"Deal base - Updated {deal.Deal.Id} inside deals");
                                            }
                                            else
                                            {
                                                Deals.Remove(Deals.First(x => x.Id == deal.Deal.Id));
                                            }

                                        dealmapping = Deals.ToDictionary(x => x.Id, y => y);
                                    }
                                }
                            }

                            if (GridView.GroupDescriptors.Any())
                                GridView.GroupDescriptors.Reset();

                            Log.Verbose($"Deal base - Updated lookup table with deal {deal.Deal.Id}");
                        }
                        catch (Exception ex)
                        {
                            Log.Error(ex, "");
                        }
                }


            });
        }
    }

锁定然后调用调度程序是否有意义,或者最好将其设置在传递给免责声明的操作中?使用队列锁是因为我使用的自定义队列只包含最新项,如果有两个具有相同ID的元素

再次感谢

1 个答案:

答案 0 :(得分:2)

是的,内部锁是多余的,因为您尝试在同一个线程中锁定同一个对象。该对象已被线程锁定,代码继续。

这里没有死锁是可能的,因为运行相同代码的另一个线程已经在外部锁定处停止并等待它被释放。如果你在内锁中锁定另一个对象而另一个线程反之亦然,则可能出现死锁。 E.g:

主题1:

lock(object2) {  // happens exactly while thread 1 is in "do something"
    //
    lock (object1) {
      // ...
    }

}

主题2:

Map.Entry

现在每个线程都在等待另一个线程释放锁。