Здравствуйте, rsn81, Вы писали:
R>PS Еще раз повторюсь, так в Java, в .NET так детально не знаю, но подозреваю, что аналогично... Потому и заинтересовала данная статья и это обсуждение.
Здравствуйте, tol05, Вы писали:
T>Здравствуйте, Mika Soukhov, Вы писали:
MS>>Потому что, как было сказано выше, считывание и запись — атомарные операции. Блокировки нужно вводить, когда вводится третье действие — операция над данными, которое содержит поле.
T>Хочу спросить: ведь Ваше высказывание справедливо только для однопроцессорных систем? Рихтер в своей книге писал, что для многопроцессорных систем из-за наличия кеширования данных процессорами могут возникнуть проблемы, особенно при записи. Поэтому он рекомендует запись обязательно синхронизировать, а чтение — на усмотрение. Какое Ваше мнение по этому поводу?
Кэши синхронизируются аппаратно независимо от локов программиста. Операция инкремента то же может быть вызвана без локов, если она осуществляется командой inc с префиском lock, который блокирует системную шину
Здравствуйте, FDSC, Вы писали:
FDS>Кэши синхронизируются аппаратно независимо от локов программиста. Операция инкремента то же может быть вызвана без локов, если она осуществляется командой inc с префиском lock, который блокирует системную шину
о команде inc с префиском lock я не слышал, если честно... Это не lock. А что? Как мне осуществить инкремент такой командой?
И еще, по Вашему получается, что volatile — лишний оператор, а Рихтер зря PowerThreading Library написал и статьи каждые несколько месяцев зря писать продолжает?
Я говорил, что в этой области не специалист, Ваши слова меня смущают.
Здравствуйте, Sinclair, Вы писали:
S>Это точно не так. S>Но зато сразу после переприсвоения, еще до отпускания старого лока, другой поток сможет легко войти в защищенную lock-ом зону, т.к. будет блокироваться на другом объекте.
Действительно, проверил:
using System;
using System.Threading;
namespace Rsdn.Threads {
public class MutableLockerTest {
private static object locker = new object();
private static bool created = false;
private static void Go() {
lock (locker) {
Console.WriteLine("Enter");
locker = new object();
if (!created) { // просьба, тут не пинать из-за отсутствия синхронизации, это просто тест
created = true;
new Thread(Go).Start();
}
Thread.Sleep(TimeSpan.FromSeconds(5));
Console.WriteLine("Exit");
}
}
private static void Main() {
Go();
}
}
}
Здравствуйте, tol05, Вы писали:
T>Здравствуйте, FDSC, Вы писали:
FDS>>Кэши синхронизируются аппаратно независимо от локов программиста. Операция инкремента то же может быть вызвана без локов, если она осуществляется командой inc с префиском lock, который блокирует системную шину T>о команде inc с префиском lock я не слышал, если честно... Это не lock. А что? Как мне осуществить инкремент такой командой? T>И еще, по Вашему получается, что volatile — лишний оператор, а Рихтер зря PowerThreading Library написал и статьи каждые несколько месяцев зря писать продолжает?
T>Я говорил, что в этой области не специалист, Ваши слова меня смущают.
Ну как сказать. Я не видел, что конкретно пишет Рихтер. lock inc — это команда процессора, если вы программируете на ассемблере, можете её применить. А как это на верхнем уровне синхронизируется, это уже другой вопрос.
Но с кэшами процессора Рихтер чего-то недопонял, если он действительно говорил, что нужна синхронизация ради кэшей...
Здравствуйте, FDSC, Вы писали:
FDS>Здравствуйте, tol05, Вы писали:
T>>Здравствуйте, Mika Soukhov, Вы писали:
MS>>>Потому что, как было сказано выше, считывание и запись — атомарные операции. Блокировки нужно вводить, когда вводится третье действие — операция над данными, которое содержит поле.
T>>Хочу спросить: ведь Ваше высказывание справедливо только для однопроцессорных систем? Рихтер в своей книге писал, что для многопроцессорных систем из-за наличия кеширования данных процессорами могут возникнуть проблемы, особенно при записи. Поэтому он рекомендует запись обязательно синхронизировать, а чтение — на усмотрение. Какое Ваше мнение по этому поводу?
FDS>Кэши синхронизируются аппаратно независимо от локов программиста. Операция инкремента то же может быть вызвана без локов, если она осуществляется командой inc с префиском lock, который блокирует системную шину
Всмысле? Не надо использовать volitale? Мучаться с memory barrier и т.д.?
недопонял
Здравствуйте, rsn81, Вы писали:
R> Я решаю эту проблему автоматическим рефакторингом: среда разработки пробегает по коду и все переменные, которые может, делает неизменяемыми.
Здравствуйте, FDSC, Вы писали:
FDS>Кэши синхронизируются аппаратно независимо от локов программиста.
И тем не менее, как оказалось, в этом отношении .NET Memory Model практически повторяет JMM:
What is the practical implication of this? Consider the standard double-locking protocol:
if (a == null) {
lock(obj) {
if (a == null) a = new A();
}
}
This is a common technique for avoiding a lock on the read of ‘a’ in the typical case. It works just fine on X86. But it would be broken by a legal but weak implementation of the ECMA CLI spec. It’s true that, according to the ECMA spec, acquiring a lock has acquire semantics and releasing a lock has release semantics.
По сути пример показывает ту же ошибку видимости, что и приводил выше в отношении Java. То есть lock в том числе и дает команду на сброс кешей. Или я вас неправильно понял?
Здравствуйте, Максим Зелинский, Вы писали:
FDS>>Кэши синхронизируются аппаратно независимо от локов программиста. Операция инкремента то же может быть вызвана без локов, если она осуществляется командой inc с префиском lock, который блокирует системную шину МЗ>Всмысле? Не надо использовать volitale? Мучаться с memory barrier и т.д.? МЗ>недопонял
Ммм, я вас то же не допонял. Мы, кажется, о разном говорим. Я всего лишь говорю, что синхронизация не требуется для записи и должна осуществляться аппаратно
What is the practical implication of this? Consider the standard double-locking protocol:
R>
if (a == null) {
R> lock(obj) {
R> if (a == null) a = new A();
R> }
R>}
This is a common technique for avoiding a lock on the read of ‘a’ in the typical case. It works just fine on X86. But it would be broken by a legal but weak implementation of the ECMA CLI spec. It’s true that, according to the ECMA spec, acquiring a lock has acquire semantics and releasing a lock has release semantics.
cbrumme's WebLog, Memory Model
R>По сути пример показывает ту же ошибку видимости, что и приводил выше в отношении Java. То есть lock в том числе и дает команду на сброс кешей. Или я вас неправильно понял
Пожалуй мне надо разобраться как lock работает
Оттуда же
In terms of the above, the memory model for X86 can be described as:
1. All stores are actually store.release.
2. All loads are normal loads.
3. Any use of the LOCK prefix (e.g. ‘LOCK CMPXCHG’ or ‘LOCK INC’) creates a full fence.
Я про выделенное. Само по себе использование префикса lock в данном случае исключает неоднозначность выполнения команды. Насколько я понимаю, вопрос только в том, будет ли компилятор использовать lock и прочие вещи синхронизации (на других архитектурах). Если он не будет сам автоматом определять, что используется многопоточность — то придётся делать локи, но, вообще, довольно странно заставлять программиста обёртывать каждую операцию записи в lock, если это операция записи элементарного типа
Здравствуйте, FDSC, Вы писали:
FDS>Ммм, я вас то же не допонял. Мы, кажется, о разном говорим. Я всего лишь говорю, что синхронизация не требуется для записи и должна осуществляться аппаратно
действительно. вот теперь понятно