Использование отдельного объекта для синхронизации

Я вижу это много:

object lockObj;
List myStrs;

// ...

lock(lockObj)
{
    myStrs.Add("hello world");
}

Зачем нужен отдельный объект? Конечно, вы можете просто сделать это:

List myStrs;

// ...

lock(myStrs)
{
    myStrs.Add("hello world");
}
2

5 ответы

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

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

See this similar question for a more detailed answer: Why is lock(this) {...} bad?

5
добавлено

В общем, избегайте блокировки открытого типа или экземпляров, находящихся вне контроля вашего кода. Общие правила блокировки (this), lock (typeof (MyType)) и lock («myLock») нарушают это правило:

     <Ол>   
  • lock (this) является проблемой, если к экземпляру можно получить доступ публично.
  •   
  • lock (typeof (MyType)) является проблемой, если MyType является общедоступным.
  •   
  • lock («myLock») является проблемой, поскольку любой другой код процесса, использующий одну и ту же строку, будет разделять одну и ту же блокировку.
  •         

    Лучшей практикой является определение закрытого объекта для блокировки или приватная переменная статического объекта для защиты данных, общих для всех экземпляров.

    Form the documentation lock c#

    2
    добавлено
    +1 - Это большие проблемы - в основном целое ", если кто-то еще увидит то, что я запираю, кто-то еще может схватить мой замок"; Вряд ли опасно использовать строку, как указано здесь, поскольку строки обычно интернированы так, что все одинаковые строки фактически являются одним и тем же объектом.
    добавлено автор JerKimball, источник

    Если вы используете этот список как объект блокировки и сбрасываете его на null , тогда блокировка (myStringList) вызовет исключение ArgumentNullException. Ниже простого тестового кода консольного приложения.

      private static IList mystringList = new List();
    
    static void Main(string[] args)
    {
        new Thread(() =>
            {
                try
                {
    
                    while (true)
                    {
                        //Acquire the lock
                        lock (mystringList)
                        {
                            //Do something with the data
                            Thread.Sleep(100);
                            Console.WriteLine("Lock acquired");
                        }
                    }
                }
                catch (Exception exception)
                {
                    Console.WriteLine("Exception: " +exception.Message);
                }
            }).Start();
    
        new Thread(() =>
            {
                //Suppose we do something
                Thread.Sleep(1000);
    
                //And by some how reset the list to null
                mystringList = null;
    
            }).Start();
    
        Console.ReadLine();
    }
    
    0
    добавлено

    Ваш список строк - это список, используемый для внутренних деталей реализации.

    Проблема со второй версией может возрасти, если вы измените свою реализацию таким образом, чтобы вы повторно инициализировали список строк.

    Тогда безопасность потоков вашей реализации может быть нарушена.

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

    0
    добавлено

    Идея состоит в том, чтобы всегда блокировать частных членов, к которым можно получить доступ только по коду, на который мы смотрим. Принимая во внимание, что когда мы блокируем членов, которых мы не контролируем, как открытый член или аналогичный, скорее всего, некоторые другие части кода уже могут содержать блокировку. Это может привести к неожиданному поведению блокировки.

    Итак, я думаю, что это привело к правилу большого пальца/лучшей практике использования частного объекта, особенно для блокировки.

    Мне было бы интересно узнать, есть ли еще причины.

    0
    добавлено
    Microsoft Stack Jobs
    Microsoft Stack Jobs
    1 788 участник(ов)

    Work & freelance only Microsoft Stack. Feed https://t.me/Microsoftstackjobsfeed Чат про F#: @Fsharp_chat Чат про C#: @CSharpChat Чат про Xamarin: @xamarin_russia Чат общения:@dotnettalks

    Microsoft Developer Community Chat
    Microsoft Developer Community Chat
    584 участник(ов)

    Чат для разработчиков и системных администраторов Microsoft Developer Community. __________ Новостной канал: @msdevru __________ Баним за: оскорбления, мат, рекламу, флуд, флейм, спам, NSFW контент, а также большое количество оффтоп тем. @banofbot