Как предотвратить взаимные блокировки в следующем коде C #? - PullRequest
2 голосов
/ 14 января 2009

Следующий класс C # используется в многопоточной среде. Я удалил очень большую часть реального кода. Проблема возникает при вызове MethodA и MethodB практически одновременно. Порядок блокировки в свойстве IsDepleted не решает проблему. Удаление блокировки (WaitingQueue) из свойства IsDepleted устраняет тупик, но это решение вызывает проблему, когда другой поток добавляет / удаляет элемент из WaitingQueue между операторами WaitingQueue.Count == 0 и Processing.Count == 0.

using System.Collections.Generic;

class Example
{
    bool IsDepleted
    {
        get
        {
            lock (Processing)
            {
                lock (WaitingQueue)
        {
                    return WaitingQueue.Count == 0
             && Processing.Count == 0;
        }
            }
        }
    }

    private readonly List<object> Processing = new List<object>();
    private readonly Queue<object> WaitingQueue = new Queue<object>();

    public void MethodA(object item)
    {
        lock (WaitingQueue)
        {
            if (WaitingQueue.Count > 0)
            {
                if (StartItem(WaitingQueue.Peek()))
                {
                    WaitingQueue.Dequeue();
                }
            }
        }
    }

    public void MethodB(object identifier)
    {
        lock (Processing)
        {
            Processing.Remove(identifier);
            if (!IsDepleted)
            {
                return;
            }
        }
    //Do something...
    }

    bool StartItem(object item)
    {
        //Do something and return a value
    }
}

Ответы [ 3 ]

3 голосов
/ 14 января 2009

Зависит от того, хотите ли вы быстрое или точное исправление.

Быстрое решение проблемы - просто использовать один объект блокировки во всех случаях.

например. private readonly object _lock = new object();

А потом просто зафиксируй это. Однако, в зависимости от вашей ситуации, это может повлиять на производительность больше, чем вы можете принять.

т.е. ваш код станет таким:

using System.Collections.Generic;

class Example
{
    private readonly object _lock = new object();

    bool IsDepleted
    {
        get
        {
            lock (_lock)
            {
                return WaitingQueue.Count == 0
                 && Processing.Count == 0;
            }
        }
    }

    private readonly List<object> Processing = new List<object>();
    private readonly Queue<object> WaitingQueue = new Queue<object>();

    public void MethodA(object item)
    {
        lock (_lock)
        {
            if (WaitingQueue.Count > 0)
            {
                if (StartItem(WaitingQueue.Peek()))
                {
                    WaitingQueue.Dequeue();
                }
            }
        }
    }

    public void MethodB(object identifier)
    {
        lock (_lock)
        {
            Processing.Remove(identifier);
            if (!IsDepleted)
            {
                return;
            }
        }
        //Do something...
    }

    bool StartItem(object item)
    {
        //Do something and return a value
    }
}
3 голосов
/ 14 января 2009

Взять блокировку обработки в методе A и блокировку WaitingQueue в методе B (другими словами, сделать так, чтобы она выглядела как первый блок кода). Таким образом, вы всегда берете замки в одном и том же порядке и никогда не будете в тупике.

2 голосов
/ 14 января 2009

Упростите свой код и используйте только один объект для блокировки. Вы также можете заменить свои замки на:

Monitor.TryEnter (обработка, 1000)

это даст вам 1 секунду. Итак, по существу:

        if (Monitor.TryEnter(Processing, 1000))
        {
            try
            {
                //do x
            }
            finally
            {
                Monitor.Exit(Processing);
            }
        }

Теперь вы не остановите тупик, но вы можете справиться со случаем, когда вы не получите блокировку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...