Немного запутанных вещей о замках
Я знаю, как использовать блокировки в своем приложении, но еще мало чего не понимаю о блокировке (BTW - я знаю, что оператор блокировки - это просто сокращенная запись для работы с типом класса Monitor).
От http://msdn.microsoft.com/en-us/library/ms173179.aspx:
public class TestThreading
{
private System.Object lockThis = new System.Object();
public void Function()
{
lock (lockThis)
{
// Access thread-sensitive resources.
}
}
}
Аргумент, предоставленный ключевому слову блокировки, должен быть объектом, основанным на ссылке type, и используется для определения области блокировки. В приведенном выше примере область блокировки ограничена этой функцией, поскольку ссылки на блокировку объекта не существуют вне функции. Если такая ссылка действительно существует, область блокировки будет распространяться на этот объект.
a) Я не понимаю, как lockThis определяет область блокировки. Область блокировки - это весь код между блокировкой (lockThis) { и смежным }, так что именно это означает, что "область блокировки будет распространяться на этот объект"?
b) Что означает термин "блокировка" для объекта lockThis? Просто мы используем ссылку на lockThis, чтобы заблокировать область кода? Таким образом, этот термин не предполагает, что мы заблокировали lockThis объект?
спасибо
Отвечая Дэвиду Мортону:
Извиняюсь, если мой ответ немного длинный, но я не мог придумать другого способа рассказать о моих вопросах и по-прежнему быть несколько последовательным:
- Объем блокировки в этой ситуации - это отдельный экземпляр самого класса. Это противоречит пересечению всего экземпляра конкретного класса. Вы можете заблокировать все блокированные экземпляры TestThreading, сделав lockThis static. То, что подразумевается под "областью" блокировки: применимо ли оно к одному экземпляру или применимо ко всем экземплярам определенного типа.
Другие объекты все равно могут получить доступ к lockThis из другого потока, но они не смогут обрабатывать код, окруженный блокировкой на этом объекте.
Если мы вызываем код, окруженный блокировкой (расположенный внутри TestThreading.Function) C, то, поскольку TestThreading.Function не является статическим, каждый экземпляр TestThreading имеет свою собственную копию C. Но если TestThreading.Function был статичным, то все экземпляры TestThreading будут иметь одну и ту же копию C. В качестве аналогии, если C является комнатой, и если TestThreading.Function не является статичным, то каждый экземпляр TestThreading будет иметь свою собственную C комнату, но если функция была статической, то все экземпляры TestThreading будут иметь одну и ту же C комнату.
Следуя этой аналогии, я интерпретирую lockThis как ключ к комнате C. Если lockThis является статическим, и если TestThreading.Function не является статичным, то все экземпляры TestThreading будут использовать один и тот же ключ для входа в собственные комнаты C.
-
Таким образом, я не вижу никакого значения в lockThis, статическом или нет, поскольку в каждом случае каждый экземпляр TestThreading будет использовать lockThis для входа в свою комнату C (предполагая, что TestThreading.Function не является статическим). Таким образом, следуя этой логике, не должна ли область блокировки быть индивидуальным экземпляром класса (предполагая, что TestThreading.Function не является статическим)?
-
Точно так же я не вижу никакого значения в lockThis, являющемся закрытым или общедоступным, так как снова экземпляр TestThreading будет использовать lockThis для ввода собственной комнаты C (предполагая, что TestThreading.Function не является статическим)
Второй ответ Дэвиду Мортону
В ответ на ваш ответ: есть значение. Если TestThreading.Function статична, то lockThis должен быть статичным, иначе TestThreading.Function не может получить доступ к lockThis вообще.
Я не уверен, что вы подразумеваете под TestThreading. Функция не может получить доступ к lockThis?! Снова предположим, что мы вызываем код, окруженный блокировкой (находящейся внутри TestThreading.Function) C.
Если TestThreading.Function статична и, следовательно, существует только одна комната, но lockThis не статична, и если мы имеем следующее определение:
public class TestThreading
{
private System.Object lockThis = new System.Object();
public static void Function()
{
lock (new TestThreading().lockThis)
{
// Access thread-sensitive resources.
}
}
}
тогда всякий раз, когда какой-либо поток будет иметь доступ к комнате C, он будет использовать новый ключ. Таким образом, если 100 потоков обратились к комнате C, то такая же комната была бы открыта с использованием 100 разных ключей?! Таким образом, код действительно работает, он просто не имеет большого смысла, поскольку между потоками не будет никакой синхронизации!
Объем блокировки в этой ситуации - это отдельный экземпляр самого класса. Это противоречит пересечению всего экземпляра конкретного класса. Вы можете заблокировать все блокировки экземпляров TestThreading, сделав lockThis static.
Я был смущен термином scope lock, так как Ive интерпретировал его как: если lockThis был статичным, то все экземпляры TestThread будут иметь одну и ту же комнату (aka lock), хотя TestThread.Function не является статичным. Предполагая, что я правильно понял это сейчас, тогда термин блокировка относится к ключу (таким образом, блокировка не относится к комнате?!), используемой для открытия дверей?
Таким образом, если мы предположим, что lockThis является статическим и TestThread.Function не является статическим, то область ключа/блокировки - это все экземпляры TestThread, что означает, что все экземпляры TestThread используют один и тот же ключ, и поэтому, когда один экземпляр TestThread открывает дверь в свою комнату с помощью этого ключа, другие экземпляры не смогут открыть двери в свои комнаты, пока первый экземпляр не выпустит этот ключ?
Третий ответ Дэвиду Мортону
Нет, если функция статична, то все экземпляры TestThread будут использовать одну и ту же комнату, если lockThis является статическим, тогда все экземпляры TestThread будут использовать один и тот же ключ.
Согласны ли вы с тем, что слово-блокировка, используемая в области предложения блокировки, по крайней мере, в некотором смысле относится к ключу (ключ является экземпляром lockThis)?
Комната - это код, который выполняется внутри замка, а не самого объекта lockThis, который просто является ключом.
[Защитный режим включен] То, что Ive сказал в моем последнем ответе.;) [Защитный режим выключен]
Ответы
Ответ 1
-
Объем блокировки в этой ситуации - это отдельный экземпляр самого класса. Это противоречит пересечению всего экземпляра конкретного класса. Вы можете заблокировать все блокированные экземпляры TestThreading, сделав lockThis static. То, что подразумевается под "областью" блокировки: применимо ли оно к одному экземпляру или применимо ко всем экземплярам определенного типа.
-
"Блокировка объекта thisObject" просто означает использование этого объекта как объекта, который определяет, находится ли мы в блокировке. Этот термин не предполагает, что мы "заблокировали" объект lockThis. Думаю, ваша оценка здесь правильная. Другие объекты могут все же получить доступ к lockThis из другого потока, но они не смогут обрабатывать код, который окружен блокировкой на этом объекте.
Поскольку мы отвечаем друг другу, здесь немного больше информации:
Давайте рассмотрим аналогию с "комнатой и ключом", описанную выше, и расширьте ее для каждой возможности. У нас есть несколько разных ситуаций:
- статическая функция, статический объект блокировки. Это аналогично наличию одной комнаты с одним ключом.
- функция экземпляра, статический объект блокировки. Это будет похоже на наличие нескольких комнат, которые используют один и тот же ключ... например, как основной ключ.
- функция экземпляра, объект блокировки экземпляра. Это будет похоже на наличие нескольких комнат, каждый из которых имеет собственный ключ... как общежитие или гостиницу.
- статическая функция, объект блокировки экземпляра - невозможно. Вы не можете получить доступ к полю экземпляра из статического контекста.
Надеемся, что в приведенных выше сценариях описывается, как они будут работать вместе.
В ответ на второй ответ
Я не уверен, что вы подразумеваете под TestThreading. Функция не может получить доступ к lockThis?!
Он не может получить доступ к полезному lockThis. Статическая блокировка метода на экземпляре, который отбрасывается при завершении блокировки, бесполезна. В сценарии, который вы настраиваете, каждый раз, когда к двери приближается, замок "отдает" новый ключ и говорит "хорошо, я принимаю ключ, который я только что дал вам... вы можете войти". В этой ситуации он слишком осторожно защищает "комнату", предоставляя каждому доступ, когда захочет. Другими словами, нет причин даже иметь оператор блокировки во втором примере. Он, как и комната, имеет динамически увеличивающееся количество дверей, которое используется только один раз, и на нем есть ключ. Бесконечное количество людей может войти, когда захочет. Нет никакой разницы между вашим кодом и следующим, действительно (есть, но это так, что вы можете надеяться получить концепцию:
public class TestThreading
{
private object lockThis = new object();
public static void Function()
{
lockThis = new object();
lock (lockThis)
{
// access something
}
}
}
То, что я сделал в этом примере выше, в основном выбрасывает и снова запирает замок прямо перед тем, как использовать его в дверях. Это не полезно. Вы правы, синхронизация потоков не будет, и в этом смысле я бы сказал, что код действительно не работает вообще, так как вся точка блокировки - синхронизация потоков.
если lockThis был статическим, тогда все Экземпляры TestThread в той же комнате (aka lock), хотя TestThread.Function не является статическим. Предполагая, что я это правильно понимаю теперь, тогда термин блокировка ссылается к ключу (таким образом, блокировка не относится к комната?!), используемый для открытия двери?
Нет, если функция статическая, то все экземпляры TestThread будут использовать одну и ту же комнату, если lockThis является статическим, тогда все экземпляры TestThread будут использовать один и тот же ключ.
lock (key)
{
// room
}
Комната - это код, который выполняется внутри замка, а не самого объекта lockThis, который просто является ключом.
Таким образом, если мы предположим, что lockThis static и TestThread.Function не статический, затем область ключа/блокировки все экземпляры TestThread, которые означает, что все экземпляры TestThread делиться одним и тем же ключом, и, таким образом, когда один Экземпляр TestThread открывает дверь его комната с использованием этого ключа, другая экземпляры не смогут открыть двери в свои комнаты до первого экземпляр выпускает этот ключ?
Да.
Ответ 2
Чтобы проиллюстрировать различия в блокировке статических или нестатических объектов, рассмотрите:
public class TestThreading
{
private object lockThis = new object();
private static object lockStatic = new object();
private Stream UIStream;
private List<int> calcStuff;
public void DoStuff1()
{
lock (lockThis)
{
// Do stuff with calcStuff that is unique to this instance
// it okay to have different instances calculating their own stuff
}
}
public void DoStuff2()
{
lock (lockStatic)
{
// Do stuff with the UI,
// which you don't want multiple threads accessing at once
}
}
}
особенно в такой ситуации, как
var A = new TestThreading();
var B = new TestThreading();
((Action)(A.DoStuff1)).BeginInvoke(null,null); // These can go concurrently
((Action)(B.DoStuff1)).BeginInvoke(null,null); // just fine
((Action)(A.DoStuff1)).BeginInvoke(null,null); // These will have to wait
((Action)(A.DoStuff1)).BeginInvoke(null,null);
((Action)(A.DoStuff2)).BeginInvoke(null,null); // These will have to wait
((Action)(B.DoStuff2)).BeginInvoke(null,null);
Ответ 3
То, о чем говорится в этом параграфе, - это то, что код имеет возможность использовать блокировку, а не как долго удерживается блокировка (которую эта статья называется длительностью блокировки).
Ответ 4
Ответ Дэвида Мортона кажется мне правильным, но для большей справки см. этот сайт: Threading in С# Это отличный ресурс для всех вещи, нарезанные в С#, включая примеры того, что не делать в нескольких случаях. Очень ясная ИМО.
Ответ 5
a) Поскольку каждый объект класса TestThreading будет иметь собственный объект "lockThis", только этот отдельный объект будет находиться в области блокировки b/c только в том, что отдельный объект может даже ссылаться на "lockThis" (b/c это личное)
b) Нет, это означает, что поскольку объект TestThreading, вызывающий блокировку, является единственным объектом, который может "блокировать" критический регион (опять же, b/c он является закрытым), "блокировка блокировки объекта" означает, что вы блокируете объект TestThreading с использованием частного типа привязки lockThis.
Например, если вместо этого вы написали это:
public class TestThreading
{
// private System.Object lockThis = new System.Object();
public void Function()
{
lock (this)
{
// Access thread-sensitive resources.
}
}
}
Не только отдельный объект сможет заблокировать объект с помощью метода Function, КАЖДЫЙ КЛАСС, КОТОРЫЙ СЛУЧАЙТЕ, что используемый объект TestThreading может заблокировать с помощью метода Function, b/c объект TestThreading предположительно будет по меньшей мере "внутренний", если не "общедоступный".