Почему блокировка (это) {& hellip;} плохая?

Вот мое субоптимальное решение, используя скрипт оболочки bash:

#!/bin/bash
# first, rename all folders
for f in `find . -depth ! -name CVS -type d`; do
   g=`dirname "$f"`/`basename "$f" | tr '[A-Z]' '[a-z]'`
   if [ "xxx$f" != "xxx$g" ]; then
      echo "Renaming folder $f"
      mv -f "$f" "$g"
   fi
done

# now, rename all files
for f in `find . ! -type d`; do
   g=`dirname "$f"`/`basename "$f" | tr '[A-Z]' '[a-z]'`
   if [ "xxx$f" != "xxx$g" ]; then
      echo "Renaming file $f"
      mv -f "$f" "$g"
   fi
done

Изменить: Я внес некоторые изменения, основанные на предложениях. Теперь все папки переименованы правильно, mv не задает вопросов, когда разрешения не совпадают, а папки CVS не переименовываются (файлы управления CVS внутри этой папки по-прежнему переименованы, к сожалению).

Edit: Since «find -depth» и «find | sort -r» возвращают список папок в удобном для использования порядке для переименования, я предпочитаю использовать «-depth» для поиска папок.

451
задан 4 revs, 4 users 59% 15 March 2014 в 19:47
поделиться

6 ответов

Это - невоспитанность для использования this в операторах блокировки, потому что это обычно находится вне контроля, кто еще мог бы соединять тот объект.

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

А частное поле обычно является более оптимальным вариантом, поскольку компилятор осуществит ограничения доступа к нему, и это будет инкапсулировать механизм блокировки. Используя this нарушает инкапсуляцию путем представления части реализации блокировки общественности. Также не ясно, что Вы будете получать блокировку на this, если это не было зарегистрировано. Даже тогда доверие документации для предотвращения проблемы является субоптимальным.

Наконец, существует распространенное заблуждение, которое lock(this) на самом деле изменяет объект, передал в качестве параметра, и в некотором роде делает его только для чтения или недоступным. Это ложь . Объект передал в качестве параметра lock, просто служит ключ . Если блокировка уже прикрепляется, что ключ, блокировка не может быть сделана; иначе блокировка позволяется.

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

Выполнение следующие C# кодируют как пример.

public class Person
{
    public int Age { get; set;  }
    public string Name { get; set; }

    public void LockThis()
    {
        lock (this)
        {
            System.Threading.Thread.Sleep(10000);
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        var nancy = new Person {Name = "Nancy Drew", Age = 15};
        var a = new Thread(nancy.LockThis);
        a.Start();
        var b = new Thread(Timewarp);
        b.Start(nancy);
        Thread.Sleep(10);
        var anotherNancy = new Person { Name = "Nancy Drew", Age = 50 };
        var c = new Thread(NameChange);
        c.Start(anotherNancy);
        a.Join();
        Console.ReadLine();
    }

    static void Timewarp(object subject)
    {
        var person = subject as Person;
        if (person == null) throw new ArgumentNullException("subject");
        // A lock does not make the object read-only.
        lock (person.Name)
        {
            while (person.Age <= 23)
            {
                // There will be a lock on 'person' due to the LockThis method running in another thread
                if (Monitor.TryEnter(person, 10) == false)
                {
                    Console.WriteLine("'this' person is locked!");
                }
                else Monitor.Exit(person);
                person.Age++;
                if(person.Age == 18)
                {
                    // Changing the 'person.Name' value doesn't change the lock...
                    person.Name = "Nancy Smith";
                }
                Console.WriteLine("{0} is {1} years old.", person.Name, person.Age);
            }
        }
    }

    static void NameChange(object subject)
    {
        var person = subject as Person;
        if (person == null) throw new ArgumentNullException("subject");
        // You should avoid locking on strings, since they are immutable.
        if (Monitor.TryEnter(person.Name, 30) == false)
        {
            Console.WriteLine("Failed to obtain lock on 50 year old Nancy, because Timewarp(object) locked on string \"Nancy Drew\".");
        }
        else Monitor.Exit(person.Name);

        if (Monitor.TryEnter("Nancy Drew", 30) == false)
        {
            Console.WriteLine("Failed to obtain lock using 'Nancy Drew' literal, locked by 'person.Name' since both are the same object thanks to inlining!");
        }
        else Monitor.Exit("Nancy Drew");
        if (Monitor.TryEnter(person.Name, 10000))
        {
            string oldName = person.Name;
            person.Name = "Nancy Callahan";
            Console.WriteLine("Name changed from '{0}' to '{1}'.", oldName, person.Name);
        }
        else Monitor.Exit(person.Name);
    }
}

Консоль произвела

'this' person is locked!
Nancy Drew is 16 years old.
'this' person is locked!
Nancy Drew is 17 years old.
Failed to obtain lock on 50 year old Nancy, because Timewarp(object) locked on string "Nancy Drew".
'this' person is locked!
Nancy Smith is 18 years old.
'this' person is locked!
Nancy Smith is 19 years old.
'this' person is locked!
Nancy Smith is 20 years old.
Failed to obtain lock using 'Nancy Drew' literal, locked by 'person.Name' since both are the same object thanks to inlining!
'this' person is locked!
Nancy Smith is 21 years old.
'this' person is locked!
Nancy Smith is 22 years old.
'this' person is locked!
Nancy Smith is 23 years old.
'this' person is locked!
Nancy Smith is 24 years old.
Name changed from 'Nancy Drew' to 'Nancy Callahan'.
482
ответ дан 6 revs, 3 users 92% 15 March 2014 в 19:47
поделиться

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

, Чтобы быть ясным, это плохо, потому что некоторый другой блок кода мог использовать экземпляр класса для блокировки, и мог бы препятствовать тому, чтобы код получил своевременную блокировку, или мог создать другие проблемы синхронизации потока. Лучший случай: ничто иное не использует ссылку на Ваш класс для блокировки. Средний случай: что-то использует ссылку на Ваш класс, чтобы сделать блокировки, и он вызывает проблемы производительности. Худший случай: что-то использует ссылку Вашего класса, чтобы сделать блокировки, и он вызывает действительно плохие, действительно тонкие, действительно трудные к отладке проблемы.

1
ответ дан Jason Jackson 15 March 2014 в 19:47
поделиться

Существует также некоторая хорошая дискуссия об этом здесь: действительно ли это - надлежащее использование взаимного исключения?

2
ответ дан 2 revs 15 March 2014 в 19:47
поделиться
  • 1
    Одна вещь, отсутствующая в этом решении, делает chmod на создании файла журнала в первый раз, когда это создается. – Cory Engebretson 14 September 2009 в 13:16

... и те же самые аргументы относятся к этой конструкции также:

lock(typeof(SomeObject))
25
ответ дан Alan 15 March 2014 в 19:47
поделиться

Смотрите на Тему MSDN , Синхронизация Потока (Руководство по программированию C#)

Обычно лучше стараться не соединять открытый тип, или на экземплярах объектов вне управления Вашего приложения. Например, заблокируйте (это) может быть проблематично, если к экземпляру можно получить доступ публично, потому что код вне Вашего управления может соединить объект также. Это могло создать ситуации с мертвой блокировкой, где два или больше потока ожидают выпуска того же объекта . Соединение общедоступного типа данных, в противоположность объекту, может вызвать проблемы по той же причине. Соединение литеральных строк особенно опасно, потому что литеральные строки интернируются общеязыковой средой выполнения (CLR). Это означает, что существует один экземпляр любого данного строкового литерала для всей программы, тот же самый объект представляет литерал во всех доменах запущенного приложения на всех потоках. В результате блокировка, помещенная на строку с тем же содержанием где угодно в процессе приложения, блокирует все экземпляры той строки в приложении. В результате лучше блокировать частного или защищенного участника, который не интернируется. Некоторые классы предоставляют участникам специально для блокировки. Тип массива, например, обеспечивает SyncRoot. Много типов набора предоставляют члену SyncRoot также.

42
ответ дан crashmstr 15 March 2014 в 19:47
поделиться

Поскольку, если люди могут достигнуть Ваш экземпляр объекта (т.е.: Ваш this), указатель, тогда они могут также попытаться заблокировать тот же самый объект. Теперь они не могли бы знать, что Вы соединяетесь this внутренне, таким образом, это может вызвать проблемы (возможно мертвая блокировка)

В дополнение к этому, это - также плохая практика, потому что это блокирует "слишком много"

, Например, у Вас могла бы быть членская переменная List<int>, и единственной вещью, которую на самом деле необходимо заблокировать, является та членская переменная. При блокировке всего объекта в функциях то другие вещи, которые вызывают те функции, будут заблокированы, ожидая блокировки. Если те функции не должны будут получать доступ к списку элементов, Вы будете заставлять другой код ожидать и замедлять Ваше приложение ни по какой причине вообще.

62
ответ дан 2 revs 15 March 2014 в 19:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: