Блокировка C # и предупреждение анализа кода CA2002 - PullRequest
7 голосов
/ 23 октября 2009

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

Мой код выглядит примерно так:

internal partial class SynchronizationForm : Form
{
    private static volatile bool workInProgress;

    private void SynchronizationForm_Shown(object sender, EventArgs e)
    {
        lock (typeof(SynchronizationForm))
        {
            if (!workInProgress)
            {
                workInProgress = true;
            }
            else
            {
                this.Close();
            }
        }
    }
}

Это работает хорошо, но когда я запускаю Анализ кода в моем проекте, я получаю следующее предупреждение:

CA2002: Microsoft.Reliability: SynchronizationForm.SynchronizationForm_Shown (object, EventArgs) блокирует ссылку типа «Тип». Замените это на блокировку объекта с сильной идентичностью.

Может кто-нибудь объяснить мне, что не так с моим кодом и как я могу улучшить его, чтобы предупреждение исчезло. Что это значит, что объект имеет сильную идентичность?

Ответы [ 4 ]

9 голосов
/ 23 октября 2009

Что плохого в том, что вы блокируете что-то общедоступное (typeof(SynchronizationForm)), которое доступно везде из вашего кода, и если какой-то другой поток блокирует эту же вещь, вы получаете тупик. В общем случае рекомендуется блокировать только частные статические объекты:

private static object _syncRoot = new object();
...
lock (_syncRoot) 
{

}

Это гарантирует вам, что только SynchronizationForm может обладать замком.

6 голосов
/ 23 октября 2009

Из MSDN объяснения правила

Считается, что объект имеет слабую идентичность, когда к нему можно получить прямой доступ через границы домена приложения. Поток, который пытается получить блокировку для объекта со слабой идентификацией, может быть заблокирован вторым потоком в другом домене приложения, который имеет блокировку для того же объекта.

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

3 голосов
/ 23 октября 2009

Проблема заключается в том, что typeof (SynchronizationForm) не является объектом частной блокировки, что означает, что любой другой фрагмент кода может использовать его для блокировки, что может привести к взаимоблокировке. Например, если какой-то другой код сделал это:

var form = new SynchronizationForm();
lock(typeof(SynchronizationForm))
{
    form.SomeMethodThatCausesSynchronizationForm_ShownToBeCalled();
}

Тогда возникнет тупик. Вместо этого вам следует удалить частный объект блокировки в классе SynchronizationForm и заблокировать его вместо этого.

2 голосов
/ 23 октября 2009

Объект System.Type класса удобно использовать в качестве блокировки взаимного исключения для статических методов класса.

Источник: http://msdn.microsoft.com/en-us/library/aa664735(VS.71).aspx

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

...