многопоточность: блокировка свойства - это правильно? - PullRequest
3 голосов
/ 31 января 2011

Я написал следующий код:

static readonly object failedTestLock = new object();

public static Dictionary<string, Exception> FailedTests
{
    get
    {
        lock (failedTestLock)
        {
            return _failedTests;
        }
    }
    set
    {
        lock (failedTestLock)
        {
            _failedTests = value;
        }
    }
}

public void RunTest(string testName)
{
    try
    {
        //Run a test
    }
    catch (Exception exception)
    {
        // ?? Is this correct / threadsafe?
        FailedTests.Add(testName, exception);
    }
}

ВОПРОС :
Это правильный способ безопасного добавления неудачного теста в словарь?
ЭтоThreadsafe?
FailedTests.Add называется ВНУТРИ блокировки или ВНЕШНЕЙ блокировки?

Можете ли вы объяснить, почему это правильно / потокобезопасно или почему нет?

Заранее спасибо

Ответы [ 4 ]

9 голосов
/ 31 января 2011

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

Это правильный способ безопасного добавления проваленный словарь в словаре?

Нет, нет, если два потока пытаются добавить в словарь одновременно. Также, если вы ожидаете, что чтение и запись происходят в определенном порядке.

Этот потокобезопасен?

Зависит от того, что вы подразумеваете под безопасным потоком , но нет, не под любым разумным определением.

FailedTests.Add называется ВНУТРИ заблокировать или за пределами блокировки?

Получение словаря (метод доступа get) происходит внутри блокировки. Этот код вызывает Add после снятия блокировки.

Можете ли вы объяснить, почему это правильно / безопасно или почему нет?

Если в вашем словаре одновременно работают несколько потоков, вы не можете предсказать порядок, в котором эти потоки изменят свое содержимое, и вы не можете контролировать, когда произойдет чтение.

7 голосов
/ 31 января 2011

Это не потокобезопасный доступ к словарю, потому что только доступ к свойству, который возвращает объект словаря, является потокобезопасным, но вы не синхронизируете вызов с методом Add. В этом случае рекомендуется использовать ConcurrentDictionary<string,Exception> или синхронизировать вызовы с Add вручную.

2 голосов
/ 31 января 2011

Вызов Add() находится за пределами блокировки.

Вы можете решить эту проблему, написав собственный метод Add () для замены свойства.

2 голосов
/ 31 января 2011

Не думаю, что это потокобезопасно, потому что блокировка сохраняется только в очень короткий момент, когда возвращается указатель на коллекцию. При добавлении в коллекцию блокировка отсутствует, поэтому, если два потока попытаются добавить одновременно, вы получите неприятную ошибку. Таким образом, вы должны заблокировать код FailedTest.Add.

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

С уважением GJ

...