Потокобезопасность инициализации Comparer<T>.Default
От: WolfHound  
Дата: 28.01.09 14:36
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>О чем ты? Это всего лишь создание дефолтного компаратора. Ну, создадут его (в вырожденном случае) 3 раза параллельно и что? Все равно они одинаковые.

VD>И на скорость это тоже влиять не будет. Так как создаются компораторы по одному для типа.
Меня не это беспокоит.

WH>>ИМХО межу этими строками нужен барьер памати

WH>>
WH>>            defaultComparer = Comparer<T>.CreateComparer();
WH>>            //вот тут
WH>>            Comparer<T>.defaultComparer = defaultComparer;
WH>>

WH>>[/паранойя]
VD>Зачем?
За тем что второй поток может увидеть указатель на компатор до того как тело компатора приедит к нему.
Для того чтобы гарантировать что второй поток полностью увидит тело компатора нужен барьер памяти.

VD>Понятно. Но красно-черное дерево автоматически барансируется и у него относительно дешёвое обновление.

Дело в том что красно-черное дерево это по сути извращенная форма 2-3 дерева.
В свою очередь 2-3 дерево это частный случай B-дерева.
А с балансировкой у B-деревьев все в порядке.
Плюс в том что 2-3 деревья плодят меньше объектов и требуют меньше вычислений при вставке.
Короче вскрытие покажет кто быстрее.

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

Ну хочется мне 2-3 дерево написать. Тебе жалко что-ли?
Вставку уже написал. Сейчас думаю как удаление сделать красиво и эффективно.

VD>Это ты о Sum(), Subtract(), Intersect() и Xor() говоришь?

VD>Там второй Set рассматривается как просто список. Так что проблем быть не должно.
При наивной реализации.
Но если действовать не в лоб, а используя свойства контейнера то можно и побыстрее... но будут проблемы с разными компаторами.


02.02.09 01:22: Ветка выделена из темы Nemerle.Collections.Set[int*char] и IComparable
Автор: Didro
Дата: 25.01.09
— VladD2
02.02.09 01:22: Перенесено модератором из 'Nemerle' — VladD2
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re: Потокобезопасность инициализации Comparer<T>.Default
От: Иванков Дмитрий Россия  
Дата: 28.01.09 20:17
Оценка:
Здравствуйте, WolfHound, Вы писали:
WH>Вставку уже написал. Сейчас думаю как удаление сделать красиво и эффективно.
Когда-то развлекался:
module MyList { //вспомогательно
 public Replace['a] (L : list['a], x : 'a, y : list['a]) : list['a];
 public indexOf['a] (L : list['a], x : 'a) : int;
}
[Record]
public class Tree {
 [Record]
 public class Node {
  public sons : list[Node];
  public isLeaf () : bool { List.IsEmpty (sons) }
  public sonsCount () : int { List.Length (sons) }
  public getBrother (s : Node) : Node * bool {
   match (MyList.indexOf (sons, s)) {
     | 0 => (List.Nth (sons, 1), true)
     | i => (List.Nth (sons, i - 1), false)
   }
  }
 };
 root : Node;
 public Replace (path : list[Node], lst : list[Node]) : Tree
 requires List.Length (lst) <= 2
//requires lst.ForAll(x => x.height () == path.Head.height ()) //примерно так
 {
   | ([_], [l]) => Tree (l)
   | ([_], [l1, l2]) => Tree (Node ([l1, l2]))
   | (q :: w :: rst, _) =>
     def l = MyList.Replace (w.sons, q, lst);
     match(List.Length (l)) {
       | 2 | 3 => Replace (w :: rst, [Node (l)])
       | 1 when List.IsEmpty (rst) => Tree (l.Head)
       | 1 =>
         def e = rst.Head;
         def ls = MyList.Replace (e.sons, w, []);
         def (b, lft) = e.getBrother (w);
         if (lft)
           Replace (b.sons.Head :: b :: rst, [l.Head, b.sons.Head])
         else
           Replace (b.sons.Last :: b :: rst, [b.sons.Last, l.Head])
       | 4 =>
         def l1 = l.FirstN (2);
         def l2 = l.ChopFirstN (2);
         Replace (w :: rst, [Node (l1), Node (l2)])
     }
 }
 public height () : int; // в лоб
 public static merge (L : Tree, R : Tree) : Tree {
  def Lh = L.height ();
  def Rh = R.height ();
  if (Lh == Rh)
   Tree (Node ([L.root, R.root]))
  else {
   if (Lh < Rh) {
    def g(n, x) {
     | (_, 0) => [n]
     | _ => n :: g (n.sons.Head, x - 1)
    }
    def p = g(R.root, Rh - Lh);
    R.Replace (p, [L.root, p.Head])
   } else {
    def g(n, x) {
     | (_, 0) => [n]
     | _ => n :: g (n.sons.Last, x - 1)
    }
    def p = g(L.root, Lh - Rh);
    L.Replace (p, [p.Head, R.root])
   }
  }
 }
};

Replace позволяет делать вставку, удаление, замену произвольного узла. На его базе + Find легко построить Set.
Merge сливает два дерева, до Split не добрался
Re: Потокобезопасность инициализации Comparer<T>.Default
От: VladD2 Российская Империя www.nemerle.org
Дата: 29.01.09 04:21
Оценка: +1
Здравствуйте, WolfHound, Вы писали:

WH>За тем что второй поток может увидеть указатель на компатор до того как тело компатора приедит к нему.

WH>Для того чтобы гарантировать что второй поток полностью увидит тело компатора нужен барьер памяти.

Я не вижу тут проблем:
public static Comparer<T> Default
{
    get
    {
        Comparer<T> defaultComparer = Comparer<T>.defaultComparer;
        if (defaultComparer == null)
        {
            defaultComparer = Comparer<T>.CreateComparer();
            Comparer<T>.defaultComparer = defaultComparer;
        }
        return defaultComparer;
    }
}

Comparer<T>.defaultComparer присваивается в самом конце когда компаратор уже сформирован.
Единственное, что может быть — параллельно сформируется два или более компаратора и только один из них останется в поле. Но это не проблема. По функциональности они будут идентичны. Так что если кто-то получит не тот компаратор, проблем это не создаст.

VD>>Понятно. Но красно-черное дерево автоматически барансируется и у него относительно дешёвое обновление.

WH>Дело в том что красно-черное дерево это по сути извращенная форма 2-3 дерева.
WH>В свою очередь 2-3 дерево это частный случай B-дерева.
WH>А с балансировкой у B-деревьев все в порядке.

Я поглядел алгоритм. С балансировкой там и правда все ОК. Память тоже видимо должна использоваться более экономично. Вопрос только в затратах на вставку/удаление.

WH>Короче вскрытие покажет кто быстрее.


Именно.

WH>Ну хочется мне 2-3 дерево написать. Тебе жалко что-ли?


Нет. Пиши на здоровье. Только интерфейс воспроизведи, чтобы можно было махнуть на ходу.

WH>Вставку уже написал. Сейчас думаю как удаление сделать красиво и эффективно.


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

VD>>Это ты о Sum(), Subtract(), Intersect() и Xor() говоришь?

VD>>Там второй Set рассматривается как просто список. Так что проблем быть не должно.
WH>При наивной реализации.
WH>Но если действовать не в лоб, а используя свойства контейнера то можно и побыстрее... но будут проблемы с разными компаторами.

Как можно что-то быстрее сделать? Ну, для Intersect или Xor еще что-то можно придумать. Но Sum и Subtract — это по любому вставка или удаление ВСЕХ элементов одного списка из другого. Так и в оригинальном списке сделано.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Потокобезопасность инициализации Comparer<T>.Default
От: WolfHound  
Дата: 29.01.09 15:26
Оценка: 12 (1)
Здравствуйте, VladD2, Вы писали:

VD>Я не вижу тут проблем:

хъ
VD>Comparer<T>.defaultComparer присваивается в самом конце когда компаратор уже сформирован.
Следи за рукам: Есть 2 разных куска памяти.
Первый содержит сам компатор. Второй содержит ссылку на компатор.
Если второй поток сначала получит второй кусок памяти и не получит первый (на некоторых архитектурах такое возможно) получим чтение не пойми чего и как следствие не пойми какие последствия. Ну ты на С++ писал...
Если вставить барьер памяти то второй поток гарантировано увидит первый кусок памяти раньше чем второй.

VD>Я поглядел алгоритм. С балансировкой там и правда все ОК. Память тоже видимо должна использоваться более экономично. Вопрос только в затратах на вставку/удаление.

Если вправить мозги компилятору будет быстрее.
Пока медленней.

VD>Там что вставка, что удаление должны выглядеть очень похоже. Сначала нужно заменить ветки от корня до вставляемой, а пром баланс поправить. Если это сделать за один проход, то будет эффективнее.

Оно сразу сбалансированным строится.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[3]: Потокобезопасность инициализации Comparer<T>.Default
От: Константин Л. Франция  
Дата: 29.01.09 15:29
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Здравствуйте, VladD2, Вы писали:


VD>>Я не вижу тут проблем:

WH>хъ
VD>>Comparer<T>.defaultComparer присваивается в самом конце когда компаратор уже сформирован.
WH>Следи за рукам: Есть 2 разных куска памяти.
WH>Первый содержит сам компатор. Второй содержит ссылку на компатор.
WH>Если второй поток сначала получит второй кусок памяти и не получит первый (на некоторых архитектурах такое возможно) получим чтение не пойми чего и как следствие не пойми какие последствия. Ну ты на С++ писал...
WH>Если вставить барьер памяти то второй поток гарантировано увидит первый кусок памяти раньше чем второй.

Такого быть не может

[]
Re[3]: Потокобезопасность инициализации Comparer<T>.Default
От: VladD2 Российская Империя www.nemerle.org
Дата: 29.01.09 17:33
Оценка:
Здравствуйте, WolfHound, Вы писали:

VD>>Comparer<T>.defaultComparer присваивается в самом конце когда компаратор уже сформирован.

WH>Следи за рукам: Есть 2 разных куска памяти.
WH>Первый содержит сам компатор. Второй содержит ссылку на компатор.
WH>Если второй поток сначала получит второй кусок памяти и не получит первый (на некоторых архитектурах такое возможно) получим чтение не пойми чего и как следствие не пойми какие последствия. Ну ты на С++ писал...
WH>Если вставить барьер памяти то второй поток гарантировано увидит первый кусок памяти раньше чем второй.

Какой еще кусок памяти? Копирование ссылочных полей в донтете операция атомарная. Что за проблемы ты находишь?

VD>>Я поглядел алгоритм. С балансировкой там и правда все ОК. Память тоже видимо должна использоваться более экономично. Вопрос только в затратах на вставку/удаление.

WH>Если вправить мозги компилятору будет быстрее.
WH>Пока медленней.

Что-то мне мне кажется, что дело не в компиляторе. КЧД компилятор не мешал. Вот компаратор действительном может затормозить все.

Ты бы код показал. Может общими усилиями получилось бы найти что в нем подтюнить.

VD>>Там что вставка, что удаление должны выглядеть очень похоже. Сначала нужно заменить ветки от корня до вставляемой, а пром баланс поправить. Если это сделать за один проход, то будет эффективнее.

WH>Оно сразу сбалансированным строится.

Замечательно. Тогда не ясно почему медленно получается.

А медленно это по сравнению с чем? Ты пробовал подменять им исходный Set и замерять скорость самосборки компилятора.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Потокобезопасность инициализации Comparer<T>.Default
От: WolfHound  
Дата: 29.01.09 18:33
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Какой еще кусок памяти? Копирование ссылочных полей в донтете операция атомарная.

Расшаренная между потоками ссылка это один кусок памяти.
Объект компатор это другой косок памяти.

VD>Что за проблемы ты находишь?

Проблемы с шареной между потоками памятью. Там на всамом деле все весело. Особенно учитывая разные модели памяти на разных процессорах.
Я знаю что у .NET'а есть своя модель памяти но где гарантия что ее на каждом конкретном процессоре корректно реализуют?
Да я и не уверен что она дает в данном конкретном случае нужные гарантии.
В любом случае race condition на лицо и как следствие нужно соломку подстелить.
nikov что скажешь?

VD>Что-то мне мне кажется, что дело не в компиляторе. КЧД компилятор не мешал. Вот компаратор действительном может затормозить все.

В нем. В чем же еще?
Переписал вставку императивненько стало на 15% быстрее родного Set'а, а было в 2 раза медленней.

VD>Ты бы код показал. Может общими усилиями получилось бы найти что в нем подтюнить.

Да я и сам могу.
В данном случае выяснил что возвращать из функции кортежи это медленно.
Пришлось возвращать через изменяемые переменные. Не красиво за-то быстро.

VD>Замечательно. Тогда не ясно почему медленно получается.

Глупый компилятор.
Причем не только немерле но и JIT.

VD>А медленно это по сравнению с чем? Ты пробовал подменять им исходный Set и замерять скорость самосборки компилятора.

Ну так я с ним и гоняюсь.
Интерфес то в той части что я сделал одинаковый.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[5]: Потокобезопасность инициализации Comparer<T>.Default
От: nikov США http://www.linkedin.com/in/nikov
Дата: 29.01.09 20:42
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Проблемы с шареной между потоками памятью. Там на всамом деле все весело. Особенно учитывая разные модели памяти на разных процессорах.

WH>Я знаю что у .NET'а есть своя модель памяти но где гарантия что ее на каждом конкретном процессоре корректно реализуют?
WH>Да я и не уверен что она дает в данном конкретном случае нужные гарантии.
WH>В любом случае race condition на лицо и как следствие нужно соломку подстелить.
WH>nikov что скажешь?

Я думаю, ты прав. Ecma-335:

12.6.8 Other memory model issues
All memory allocated for static variables (other than those assigned RVAs within a PE file, see Partition II) and
objects shall be zeroed before they are made visible to any user code.
A conforming implementation of the CLI shall ensure that, even in a multi-threaded environment and without
proper user synchronization, objects are allocated in a manner that prevents unauthorized memory access and
prevents invalid operations from occurring. In particular, on multiprocessor memory systems where explicit
synchronization is required to ensure that all relevant data structures are visible (for example, vtable pointers)
the Execution Engine shall be responsible for either enforcing this synchronization automatically or for
converting errors due to lack of synchronization into non-fatal, non-corrupting, user-visible exceptions.
It is explicitly not a requirement that a conforming implementation of the CLI guarantee that all state updates
performed within a constructor be uniformly visible before the constructor completes. CIL generators can
ensure this requirement themselves by inserting appropriate calls to the memory barrier or volatile write
instructions.


То есть, самое худшее, что может случиться по стандарту — неожиданное исключение, потому что поток "увидит" по ссылке память, заполненную нулями (в т.ч. служебные поля объекта). Но насколько мне известно, реализация MS устроена так, что write выполняется как volatile write.
Re[5]: Потокобезопасность инициализации Comparer<T>.Default
От: VladD2 Российская Империя www.nemerle.org
Дата: 29.01.09 23:46
Оценка:
Здравствуйте, WolfHound, Вы писали:

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

Если бы проблемы были, то форумы давно были бы завалены вопросами "почему у меня глючит ... при вызове из двух потоков".

В общем, класс писал не ты. Оставь это тем кто его писал. Можешь им даже свои мыли изложить.
Но нельзя браться за сто дел сразу. Ни одного не сделаешь ведь. Так что забей на это.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Потокобезопасность инициализации Comparer<T>.Default
От: WolfHound  
Дата: 30.01.09 04:29
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Если бы проблемы были, то форумы давно были бы завалены вопросами "почему у меня глючит ... при вызове из двух потоков".

Это гейзенбаг. Его не так то просто увидить.
Но он есть и его надо фиксить.

VD>В общем, класс писал не ты. Оставь это тем кто его писал. Можешь им даже свои мыли изложить.

Тут есть nikov. Он может им передать.
Тем более что он со мной согласен.
Кстати хорошая иллюстрация на тему что многопоточность на шареной памяти мало кто понимает.

VD>Но нельзя браться за сто дел сразу. Ни одного не сделаешь ведь. Так что забей на это.

А можно я сам разберусь сколько мне дел одновременно делать?
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[6]: Потокобезопасность инициализации Comparer<T>.Default
От: nikov США http://www.linkedin.com/in/nikov
Дата: 30.01.09 10:01
Оценка: +2
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, WolfHound, Вы писали:

VD>Слушай кончай антазировать. Нет там никаких проблем. Копирование ссылки — атомарная операция. Объект сначала формируется, а потом ссылка на него помещается в переменную.
По спецификации — вовсе не обязательно. В многопроцессорной среде понятия сначала/потом являются отностительными. Если реализация MS сейчас ведет себя более безопасно, то это не значит, что она будет вести себя так завтра на 32-процессорной машине, или что другие моно/шмоно будут себя так вести. Это предупреждение в спецификацию неспроста вставили.
Однако, благодаря предварительному обнулению кучи, самое худшее, что может случиться — это исключение. Никакого повреждения памяти или получения постороннего объекта.
Re[7]: Потокобезопасность инициализации Comparer<T>.Default
От: Константин Л. Франция  
Дата: 30.01.09 10:21
Оценка:
Здравствуйте, nikov, Вы писали:

N>Здравствуйте, VladD2, Вы писали:


VD>>Здравствуйте, WolfHound, Вы писали:

VD>>Слушай кончай антазировать. Нет там никаких проблем. Копирование ссылки — атомарная операция. Объект сначала формируется, а потом ссылка на него помещается в переменную.
N>По спецификации — вовсе не обязательно. В многопроцессорной среде понятия сначала/потом являются отностительными. Если реализация MS сейчас ведет себя более безопасно, то это не значит, что она будет вести себя так завтра на 32-процессорной машине, или что другие моно/шмоно будут себя так вести. Это предупреждение в спецификацию неспроста вставили.
N>Однако, благодаря предварительному обнулению кучи, самое худшее, что может случиться — это исключение. Никакого повреждения памяти или получения постороннего объекта.

Так. Стоп. Что значит сначала/потом. Давайте разберемся как будет создаваться объект.

1. Выделяется память
2. На ней зовется ctor
3. Ссылка на память присваивается переменной

Вы патаетесь сказать, что порядок может быть 1,3,2? Какой в этом смысл?
Re[8]: Потокобезопасность инициализации Comparer<T>.Default
От: nikov США http://www.linkedin.com/in/nikov
Дата: 30.01.09 10:28
Оценка:
Здравствуйте, Константин Л., Вы писали:

КЛ>Так. Стоп. Что значит сначала/потом. Давайте разберемся как будет создаваться объект.


КЛ>1. Выделяется память

КЛ>2. На ней зовется ctor
КЛ>3. Ссылка на память присваивается переменной

КЛ>Вы патаетесь сказать, что порядок может быть 1,3,2? Какой в этом смысл?


Порядок, в котором другой поток, выполняющийся на другом проце с другими кэшами, увидит эти изменения может быть другим. Смысл — ускорить работу за счет снижения гарантий. Тот, кому нужны гарантии — вставляет ручную синхронизацию и барьеры (например, их могут вставлять компиляторы из языков высокго уровня в IL) и профилирует замедление.
Re[9]: Потокобезопасность инициализации Comparer<T>.Default
От: Константин Л. Франция  
Дата: 30.01.09 10:35
Оценка:
Здравствуйте, nikov, Вы писали:

N>Здравствуйте, Константин Л., Вы писали:


КЛ>>Так. Стоп. Что значит сначала/потом. Давайте разберемся как будет создаваться объект.


КЛ>>1. Выделяется память

КЛ>>2. На ней зовется ctor
КЛ>>3. Ссылка на память присваивается переменной

КЛ>>Вы патаетесь сказать, что порядок может быть 1,3,2? Какой в этом смысл?


N>Порядок, в котором другой поток, выполняющийся на другом проце с другими кэшами, увидит эти изменения может быть другим. Смысл — ускорить работу за счет снижения гарантий. Тот, кому нужны гарантии — вставляет ручную синхронизацию и барьеры (например, их могут вставлять компиляторы из языков высокго уровня в IL) и профилирует замедление.


А до п. 3 других потоков эти изменения не интересуют. Точнее так: они полюбому должны увидеть что память выделилась, иначе ничего работать не будет, им пофиг, вызвался ctor или нет, им пофиг, что они увидять не сразу, что статическая переменная уже ссылается на объект
Re[8]: Потокобезопасность инициализации Comparer<T>.Default
От: WolfHound  
Дата: 30.01.09 10:38
Оценка: +1
Здравствуйте, Константин Л., Вы писали:

КЛ>Вы патаетесь сказать, что порядок может быть 1,3,2? Какой в этом смысл?

Нет.
Операции идут последовательно.
НО! Каждая из них модифицирует разные области памяти.
И результат модификации этих областей в другом потоке может быть виден в другом порядке.
Чтобы этого небыло нужно дергать барьер памяти.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[9]: Потокобезопасность инициализации Comparer<T>.Default
От: Константин Л. Франция  
Дата: 30.01.09 10:41
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Здравствуйте, Константин Л., Вы писали:


КЛ>>Вы патаетесь сказать, что порядок может быть 1,3,2? Какой в этом смысл?

WH>Нет.
WH>Операции идут последовательно.
WH>НО! Каждая из них модифицирует разные области памяти.
WH>И результат модификации этих областей в другом потоке может быть виден в другом порядке.
WH>Чтобы этого небыло нужно дергать барьер памяти.

тогда никаких проблем быть не может. главное что выделение памяти потоки видят одновременно.
Re[10]: Потокобезопасность инициализации Comparer<T>.Default
От: nikov США http://www.linkedin.com/in/nikov
Дата: 30.01.09 10:45
Оценка:
Здравствуйте, Константин Л., Вы писали:

КЛ>А до п. 3 других потоков эти изменения не интересуют. Точнее так: они полюбому должны увидеть что память выделилась, иначе ничего работать не будет, им пофиг, вызвался ctor или нет, им пофиг, что они увидять не сразу, что статическая переменная уже ссылается на объект


Я не совсем понимаю, что значит "увидеть что память выделилась". Может быть так, что статическая переменная уже ссылается на объект A, но память в куче, где этот объект должен лежать, с точки зрения какого-то потока еще заполнена нулями (хотя на самом деле конструктор уже отработал). И этот поток может словить исключение при вызове метода объекта A. Но если этот поток попробует создать какой-то другой объект, то он будет корректно размещен в куче после объекта А, потому что правильная работа кучи гарантируется без ручных блокировок (это и есть "увидеть что память выделилась"?).
Re[10]: Потокобезопасность инициализации Comparer<T>.Default
От: WolfHound  
Дата: 30.01.09 10:46
Оценка:
Здравствуйте, Константин Л., Вы писали:

КЛ>тогда никаких проблем быть не может. главное что выделение памяти потоки видят одновременно.

Ну если работа с объектом находящемся в произвольном состоянии включая служебные поля не проблема тогда что же для тебя проблема?
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[11]: Потокобезопасность инициализации Comparer<T>.Default
От: Константин Л. Франция  
Дата: 30.01.09 10:49
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Здравствуйте, Константин Л., Вы писали:


КЛ>>тогда никаких проблем быть не может. главное что выделение памяти потоки видят одновременно.

WH>Ну если работа с объектом находящемся в произвольном состоянии включая служебные поля не проблема тогда что же для тебя проблема?

Где он находится в произвольном состоянии? Еще раз.

1. выделяем память (тут _все_ потоки должны это увидеть)
2. инициализируем объект (тут пофиг, ибо живых ссылок пока на эту память в проге нет, другим потокам на эту память о объект пофиг)
3. инициализируем статическую переменную ссылкой на объект

м?
Re[11]: Потокобезопасность инициализации Comparer<T>.Default
От: Константин Л. Франция  
Дата: 30.01.09 10:53
Оценка:
Здравствуйте, nikov, Вы писали:

N>Здравствуйте, Константин Л., Вы писали:


КЛ>>А до п. 3 других потоков эти изменения не интересуют. Точнее так: они полюбому должны увидеть что память выделилась, иначе ничего работать не будет, им пофиг, вызвался ctor или нет, им пофиг, что они увидять не сразу, что статическая переменная уже ссылается на объект


N>Я не совсем понимаю, что значит "увидеть что память выделилась".


Это значит, что все потоки имеют правильную информацию о значении того преславутого курсора в мэнеджед хипе.

N>Может быть так, что статическая переменная уже ссылается на объект A, но память в куче, где этот объект должен лежать, с точки зрения какого-то потока еще заполнена нулями (хотя на самом деле конструктор уже отработал). И этот поток может словить исключение при вызове метода объекта A. Но если этот поток попробует создать какой-то другой объект, то он будет корректно размещен в куче после объекта А, потому что правильная работа кучи гарантируется без ручных блокировок (это и есть "увидеть что память выделилась"?).


Такого быть не может.
Re[12]: Потокобезопасность инициализации Comparer<T>.Default
От: nikov США http://www.linkedin.com/in/nikov
Дата: 30.01.09 10:54
Оценка: +1
Здравствуйте, Константин Л., Вы писали:

КЛ>1. выделяем память (тут _все_ потоки должны это увидеть)

"Выделяем память" в .NET — это просто увеличение указателя на начало свободной области в куче, причем гарантируется, что это изменение любой поток увидит прежде, чем он попытается создать какой-то другой объект.

КЛ>2. инициализируем объект (тут пофиг, ибо живых ссылок пока на эту память в проге нет, другим потокам на эту память о объект пофиг)

А вот это изменение другие потоки могут увидеть с запозданием, вместо этого видя память, заполненную нулями.

КЛ>3. инициализируем статическую переменную ссылкой на объект

Это изменение другие потоки тоже могут увидеть с запозданием, которое может быть как больше, так и меньше предыдущего запоздания.
Re[12]: Потокобезопасность инициализации Comparer<T>.Default
От: nikov США http://www.linkedin.com/in/nikov
Дата: 30.01.09 10:55
Оценка:
Здравствуйте, Константин Л., Вы писали:

N>>Я не совсем понимаю, что значит "увидеть что память выделилась".

КЛ>Это значит, что все потоки имеют правильную информацию о значении того преславутого курсора в мэнеджед хипе.

Да, это гарантируется.

N>>Может быть так, что статическая переменная уже ссылается на объект A, но память в куче, где этот объект должен лежать, с точки зрения какого-то потока еще заполнена нулями (хотя на самом деле конструктор уже отработал). И этот поток может словить исключение при вызове метода объекта A. Но если этот поток попробует создать какой-то другой объект, то он будет корректно размещен в куче после объекта А, потому что правильная работа кучи гарантируется без ручных блокировок (это и есть "увидеть что память выделилась"?).


КЛ>Такого быть не может.


Какие у тебя аргументы? У меня — четкое предупреждение в спецификации.
Re[13]: Потокобезопасность инициализации Comparer<T>.Default
От: Константин Л. Франция  
Дата: 30.01.09 10:57
Оценка:
Здравствуйте, nikov, Вы писали:

N>Здравствуйте, Константин Л., Вы писали:


КЛ>>1. выделяем память (тут _все_ потоки должны это увидеть)

N>"Выделяем память" в .NET — это просто увеличение указателя на начало свободной области в куче, причем гарантируется, что это изменение любой поток увидит прежде, чем он попытается создать какой-то другой объект.

то, что это "просто" я в курсе, написал об этом выше WolfHound'у

КЛ>>2. инициализируем объект (тут пофиг, ибо живых ссылок пока на эту память в проге нет, другим потокам на эту память о объект пофиг)

N>А вот это изменение другие потоки могут увидеть с запозданием, вместо этого видя память, заполненную нулями.

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

КЛ>>3. инициализируем статическую переменную ссылкой на объект

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

и тут нет проблем
Re[13]: Потокобезопасность инициализации Comparer<T>.Default
От: Константин Л. Франция  
Дата: 30.01.09 11:00
Оценка:
Здравствуйте, nikov, Вы писали:

N>Здравствуйте, Константин Л., Вы писали:


N>>>Я не совсем понимаю, что значит "увидеть что память выделилась".

КЛ>>Это значит, что все потоки имеют правильную информацию о значении того преславутого курсора в мэнеджед хипе.

N>Да, это гарантируется.


ясное дело, иначе ничего бы не работало

N>>>Может быть так, что статическая переменная уже ссылается на объект A, но память в куче, где этот объект должен лежать, с точки зрения какого-то потока еще заполнена нулями (хотя на самом деле конструктор уже отработал). И этот поток может словить исключение при вызове метода объекта A. Но если этот поток попробует создать какой-то другой объект, то он будет корректно размещен в куче после объекта А, потому что правильная работа кучи гарантируется без ручных блокировок (это и есть "увидеть что память выделилась"?).


КЛ>>Такого быть не может.


N>Какие у тебя аргументы? У меня — четкое предупреждение в спецификации.


Такие, что порядок создания объектов строго (?) определен, и мы не можем "запаблишить" ссылку для, так скажем, юзер кода, которая ссылается на неинициализированный объект. Впрочем, переведи плиз на русский эту выдержеку, может быть я не так её понял.
Re[14]: Потокобезопасность инициализации Comparer<T>.Default
От: nikov США http://www.linkedin.com/in/nikov
Дата: 30.01.09 11:01
Оценка:
Здравствуйте, Константин Л., Вы писали:

КЛ>>>2. инициализируем объект (тут пофиг, ибо живых ссылок пока на эту память в проге нет, другим потокам на эту память о объект пофиг)

N>>А вот это изменение другие потоки могут увидеть с запозданием, вместо этого видя память, заполненную нулями.

КЛ>У других потоков еще нет ссылки на этот объект, зачем им что-то видеть?

Представь, что поток T увидит память ненулевой с задержкой в 3 мс.

КЛ>>>3. инициализируем статическую переменную ссылкой на объект

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

КЛ>и тут нет проблем

А изменение статической переменной поток T увидит с задержкой в 1 мс. После этого сразу пытается вызвать метод объекта по этой ссылке. А вместо объекта — еще нули (предыдущая задержка в 3 мс еще не кончилась). Исключение.
Re[15]: Потокобезопасность инициализации Comparer<T>.Default
От: Константин Л. Франция  
Дата: 30.01.09 11:08
Оценка:
Здравствуйте, nikov, Вы писали:

N>Здравствуйте, Константин Л., Вы писали:


КЛ>>>>2. инициализируем объект (тут пофиг, ибо живых ссылок пока на эту память в проге нет, другим потокам на эту память о объект пофиг)

N>>>А вот это изменение другие потоки могут увидеть с запозданием, вместо этого видя память, заполненную нулями.

КЛ>>У других потоков еще нет ссылки на этот объект, зачем им что-то видеть?

N>Представь, что поток T увидит память ненулевой с задержкой в 3 мс.

Какую память? Поток Т еще не имеет (!) ссылки на этот объект. Откуда он может увидеть что за этой ссылкой кроется?

КЛ>>>>3. инициализируем статическую переменную ссылкой на объект

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

КЛ>>и тут нет проблем

N>А изменение статической переменной поток T увидит с задержкой в 1 мс. После этого сразу пытается вызвать метод объекта по этой ссылке. А вместо объекта — еще нули (предыдущая задержка в 3 мс еще не кончилась). Исключение.

comparer = new Comparer();
левая часть — правая часть

поток Т ничего не сможет "увидеть" пока правая часть не отработает. а как раз в правой часто происходит все самое важное — new, ctor. поток Т может обратиться к объекту через comparer только после того, как объект полностью сконструирован. Т.е. через 1 мс для T comparer будет все еще null. Все. Откуда тут проблемы? Нету тут проблем.
Re[16]: Потокобезопасность инициализации Comparer<T>.Default
От: nikov США http://www.linkedin.com/in/nikov
Дата: 30.01.09 11:15
Оценка: +1
Здравствуйте, Константин Л., Вы писали:

КЛ>>>У других потоков еще нет ссылки на этот объект, зачем им что-то видеть?

N>>Представь, что поток T увидит память ненулевой с задержкой в 3 мс.

КЛ>Какую память? Поток Т еще не имеет (!) ссылки на этот объект. Откуда он может увидеть что за этой ссылкой кроется?

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

N>>А изменение статической переменной поток T увидит с задержкой в 1 мс. После этого сразу пытается вызвать метод объекта по этой ссылке. А вместо объекта — еще нули (предыдущая задержка в 3 мс еще не кончилась). Исключение.


КЛ>comparer = new Comparer();

КЛ>левая часть — правая часть

КЛ>поток Т ничего не сможет "увидеть" пока правая часть не отработает. а как раз в правой часто происходит все самое важное — new, ctor. поток Т может обратиться к объекту через comparer только после того, как объект полностью сконструирован.

Объект сконструирован — это значит он записан в память некоторым потоком. Другие потоки могут увидеть обновление этой памяти с опозданием.

КЛ>Т.е. через 1 мс для T comparer будет все еще null. Все. Откуда тут проблемы? Нету тут проблем.


Ты понимаешь, что ссылка на объект и сам объект находятся в совершенно разных участках памяти? Изменения этих участков могут быть видны другим потокам с задержками. С разными задержками.
Re[14]: перевод
От: Константин Л. Франция  
Дата: 30.01.09 11:24
Оценка:
Здравствуйте, Константин Л., Вы писали:

[]


Память, выделенная для статических переменных и объектов должна быть обнулена прежде, чем они буду доступны любому юзер-коду.
Правильная имплементация CLI должна гарантировать, что даже в многопоточном окружении и без соответствующей синхронизации в юзер-коде, объекты создаются таким образом, что доступ к памяти и операции с ней всегда валидны. (1) На МП системах, где требуется явная синхронизация, Execution Engine отвечает за автоматическое обеспечение этой синхронизации или за выброс в юзер-моуд исключений вместо обеспечения этой синхронизации.
Правильная имплементация CLI совершенно не обязана гарантировать, что все изменение состояния, происходящие в конструкторе, должны быть одинаково видны пока конструктор не отработает.(2) CIL свободен давать такие гарантии по своему усмотрению.


Итак.

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

В общем, ничего существенного этот абзац нам не дает.
Re[17]: Потокобезопасность инициализации Comparer<T>.Default
От: Константин Л. Франция  
Дата: 30.01.09 11:27
Оценка:
Здравствуйте, nikov, Вы писали:

N>Здравствуйте, Константин Л., Вы писали:


КЛ>>>>У других потоков еще нет ссылки на этот объект, зачем им что-то видеть?

N>>>Представь, что поток T увидит память ненулевой с задержкой в 3 мс.

КЛ>>Какую память? Поток Т еще не имеет (!) ссылки на этот объект. Откуда он может увидеть что за этой ссылкой кроется?

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

Если спецификация CLI такой гарантии на дает, значит это

N>>>А изменение статической переменной поток T увидит с задержкой в 1 мс. После этого сразу пытается вызвать метод объекта по этой ссылке. А вместо объекта — еще нули (предыдущая задержка в 3 мс еще не кончилась). Исключение.


КЛ>>comparer = new Comparer();

КЛ>>левая часть — правая часть

КЛ>>поток Т ничего не сможет "увидеть" пока правая часть не отработает. а как раз в правой часто происходит все самое важное — new, ctor. поток Т может обратиться к объекту через comparer только после того, как объект полностью сконструирован.

N>Объект сконструирован — это значит он записан в память некоторым потоком. Другие потоки могут увидеть обновление этой памяти с опозданием.

КЛ>>Т.е. через 1 мс для T comparer будет все еще null. Все. Откуда тут проблемы? Нету тут проблем.


N>Ты понимаешь, что ссылка на объект и сам объект находятся в совершенно разных участках памяти? Изменения этих участков могут быть видны другим потокам с задержками. С разными задержками.


Понимаю, но опять же, если CLI не дает такой гарантии, то это звиздец. Это такой звиздец, что .net идет в лес и не возвращается.
Re[15]: перевод
От: nikov США http://www.linkedin.com/in/nikov
Дата: 30.01.09 11:38
Оценка:
Здравствуйте, Константин Л., Вы писали:


КЛ>

КЛ>Память, выделенная для статических переменных и объектов должна быть обнулена прежде, чем они буду доступны любому юзер-коду.
КЛ>Правильная имплементация CLI должна гарантировать, что даже в многопоточном окружении и без соответствующей синхронизации в юзер-коде, объекты создаются таким образом, что доступ к памяти и операции с ней всегда валидны. (1) На МП системах, где требуется явная синхронизация, Execution Engine отвечает за автоматическое обеспечение этой синхронизации или за выброс в юзер-моуд исключений вместо обеспечения этой синхронизации.
КЛ>Правильная имплементация CLI совершенно не обязана гарантировать, что все изменение состояния, происходящие в конструкторе, должны быть одинаково видны пока конструктор не отработает.(2) CIL свободен давать такие гарантии по своему усмотрению.



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

Да, ты не можешь получить "мусор" с сылками на посторонние области памяти (что могло бы привести к повреждению структур данных, например, в другом домене).

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

Вместо этого, они могут стать видны в какой-то момент после того, как конструктор отработает. Из-за этого другой поток может увидеть недоконструированный или вообще состоящий из нулей объект...

или за выброс в юзер-моуд исключений вместо обеспечения этой синхронизации

... что может привести к исключению.

Если ты не согласен, то объясни, о каких исключениях идет речь.
Re[18]: Потокобезопасность инициализации Comparer<T>.Default
От: nikov США http://www.linkedin.com/in/nikov
Дата: 30.01.09 11:43
Оценка:
Здравствуйте, Константин Л., Вы писали:

КЛ>Если спецификация CLI такой гарантии на дает, значит это


На самом деле это всего лишь значит, что надо использовать volatile поля или барьеры памяти или блокировки там, где это существенно.
Re[19]: Потокобезопасность инициализации Comparer<T>.Default
От: Константин Л. Франция  
Дата: 30.01.09 11:49
Оценка:
Здравствуйте, nikov, Вы писали:

N>Здравствуйте, Константин Л., Вы писали:


КЛ>>Если спецификация CLI такой гарантии на дает, значит это


N>На самом деле это всего лишь значит, что надо использовать volatile поля или барьеры памяти или блокировки там, где это существенно.


Давай продолжим тут, ибо мы вроде теперь имеем одну тему для обсуждения.

Итак, проблема звучит след. образом — "момент паблишинга ссылки на объект может не совпадать с моментом паблишинга памяти объекта". (сорри, если паблишинг вам не нравится, но мне кажется удачное слово).

Имхо, если это действительно так, то вопрос "где это существенно" вообще не должен стоять, ибо мы на ровном месте (!) можем получить не просто "старый" объект, а еще и исключение.

В связи с этим мне оч интересно, как тут будет работать GС? Между этими твоими 1 мс и 3 мс? Или перед тем, как стопать треды, он делает сброс кешей?
Re[20]: Потокобезопасность инициализации Comparer<T>.Default
От: nikov США http://www.linkedin.com/in/nikov
Дата: 30.01.09 12:19
Оценка:
Здравствуйте, Константин Л., Вы писали:

КЛ>В связи с этим мне оч интересно, как тут будет работать GС? Между этими твоими 1 мс и 3 мс? Или перед тем, как стопать треды, он делает сброс кешей?


С точки зрения Ecma-335, GC почти полностью непрозрачный механизм. Просто гарантируется, что он работает правильно (рано или поздно удаляет все мертвые объекты, и не портит живые), если код соблюдает определенные правила работы с указателями (а в верифицируемом коде они автоматичеси соблюдаются). Я думаю, что он синхронизирует кэши.
Re[21]: Потокобезопасность инициализации Comparer<T>.Default
От: Константин Л. Франция  
Дата: 30.01.09 12:24
Оценка:
Здравствуйте, nikov, Вы писали:

N>Здравствуйте, Константин Л., Вы писали:


[]

Допустим, но сам посуди, это же бред — ссылка новая доступна, память по ней — старая. Ссылка новая доступна — значит кеш инвалидировался (строка) -> наверняка память тоже, тк, я думаю, для скрости работы ссылка и сама память должны лежать в одной линейке кеша. Кароче, это что-то из ряда фантастики. Как тогда проги писать, простите?
Re[22]: Потокобезопасность инициализации Comparer<T>.Default
От: nikov США http://www.linkedin.com/in/nikov
Дата: 30.01.09 12:30
Оценка:
Здравствуйте, Константин Л., Вы писали:

КЛ>Допустим, но сам посуди, это же бред — ссылка новая доступна, память по ней — старая. Ссылка новая доступна — значит кеш инвалидировался (строка) -> наверняка память тоже, тк, я думаю, для скрости работы ссылка и сама память должны лежать в одной линейке кеша.


Ну это уж как получится.

КЛ>Кароче, это что-то из ряда фантастики. Как тогда проги писать, простите?

Далеко не все проги многопоточные. А многопоточные используют синхронизацию или вообще высокоуровневые феймворки, в которых уже все продумано и протестировано.
Re[23]: Потокобезопасность инициализации Comparer<T>.Default
От: Константин Л. Франция  
Дата: 30.01.09 12:34
Оценка:
Здравствуйте, nikov, Вы писали:

N>Здравствуйте, Константин Л., Вы писали:


КЛ>>Допустим, но сам посуди, это же бред — ссылка новая доступна, память по ней — старая. Ссылка новая доступна — значит кеш инвалидировался (строка) -> наверняка память тоже, тк, я думаю, для скрости работы ссылка и сама память должны лежать в одной линейке кеша.


N>Ну это уж как получится.


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

КЛ>>Кароче, это что-то из ряда фантастики. Как тогда проги писать, простите?

N>Далеко не все проги многопоточные. А многопоточные используют синхронизацию или вообще высокоуровневые феймворки, в которых уже все продумано и протестировано.

Боюсь тебя огорчить, но практически никто не закладывается на такие эффекты, и часто вообще не используют volatile. Даже MS
Re[22]: Потокобезопасность инициализации Comparer<T>.Default
От: WolfHound  
Дата: 30.01.09 13:07
Оценка:
Здравствуйте, Константин Л., Вы писали:

КЛ>Допустим, но сам посуди, это же бред — ссылка новая доступна, память по ней — старая.

Все нормально.
Две разные области памяти обновились в разные моменты времени.

КЛ>Ссылка новая доступна — значит кеш инвалидировался (строка) -> наверняка память тоже, тк, я думаю, для скрости работы ссылка и сама память должны лежать в одной линейке кеша.

С какой это стати статическая переменная и объект ссылку на который в эту переменную запишут попадут в одну линейку кеша?

КЛ>Кароче, это что-то из ряда фантастики.

Обычное дело.

КЛ>Как тогда проги писать, простите?

Нужно понимать как устроена многопоточность.

Для того чтобы таких выкрутасов небыло есть барьеры памяти.
В мьютексы они встроены.

Если бы там стоял lock вопросов бы небыло.
А тут народ вобще попытался wait free сделать.
Так что если занялся особой многопоточной магией изучи как она работает.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[23]: Потокобезопасность инициализации Comparer<T>.Default
От: Константин Л. Франция  
Дата: 30.01.09 13:17
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Здравствуйте, Константин Л., Вы писали:


КЛ>>Допустим, но сам посуди, это же бред — ссылка новая доступна, память по ней — старая.

WH>Все нормально.
WH>Две разные области памяти обновились в разные моменты времени.

КЛ>>Ссылка новая доступна — значит кеш инвалидировался (строка) -> наверняка память тоже, тк, я думаю, для скрости работы ссылка и сама память должны лежать в одной линейке кеша.

WH>С какой это стати статическая переменная и объект ссылку на который в эту переменную запишут попадут в одну линейку кеша?

я сказал _может_

КЛ>>Кароче, это что-то из ряда фантастики.

WH>Обычное дело.

КЛ>>Как тогда проги писать, простите?

WH>Нужно понимать как устроена многопоточность.

Прости, но сказать "Нужно понимать как устроена многопоточность" все равно что сказать "Нужно понимать как устроена физика". Т.е. ничего не сказать.

WH>Для того чтобы таких выкрутасов небыло есть барьеры памяти.

WH>В мьютексы они встроены.

WH>Если бы там стоял lock вопросов бы небыло.

WH>А тут народ вобще попытался wait free сделать.
WH>Так что если занялся особой многопоточной магией изучи как она работает.

Гм, пока ты не привел ни одного доказательства. Ты говоришь всего-лишь как это может быть, но ничего не говоришь про платформу и тд. У платформы своя пляска (smp, numa), а у FW другая. На данный момент неясно, какая у FW, и как она зависит от underlying memory model
Re[23]: Потокобезопасность инициализации Comparer<T>.Default
От: Константин Л. Франция  
Дата: 30.01.09 13:21
Оценка:
Здравствуйте, WolfHound, Вы писали:

[]

КЛ>>Ссылка новая доступна — значит кеш инвалидировался (строка) -> наверняка память тоже, тк, я думаю, для скрости работы ссылка и сама память должны лежать в одной линейке кеша.

WH>С какой это стати статическая переменная и объект ссылку на который в эту переменную запишут попадут в одну линейку кеша?

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

[]
Re[7]: Потокобезопасность инициализации Comparer<T>.Default
От: VladD2 Российская Империя www.nemerle.org
Дата: 30.01.09 15:15
Оценка:
Здравствуйте, nikov, Вы писали:

N>Однако, благодаря предварительному обнулению кучи, самое худшее, что может случиться — это исключение. Никакого повреждения памяти или получения постороннего объекта.


Не может там быть никакого исключения. Как оно там произойдет?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: Потокобезопасность инициализации Comparer<T>.Default
От: VladD2 Российская Империя www.nemerle.org
Дата: 30.01.09 15:18
Оценка:
Здравствуйте, nikov, Вы писали:

N>Порядок, в котором другой поток, выполняющийся на другом проце с другими кэшами, увидит эти изменения может быть другим. Смысл — ускорить работу за счет снижения гарантий. Тот, кому нужны гарантии — вставляет ручную синхронизацию и барьеры (например, их могут вставлять компиляторы из языков высокго уровня в IL) и профилирует замедление.


Не может он быть другим. Или другой поток увидит null и войдет в if или не увидит и получит ссылку на сформированный объект.

Кончайте выдумывать. И вообще, проблемы дефолтного компаратора — это проблемы МС, так как они его писали. Можете создать описание бага и посмотреть что вам ответят.

К данной же теме это не имеет никакого отношения.

ЗЫ

Что за привычка любой разговор в диспут превращать? Так ничего в жизни не сделаешь.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[15]: перевод
От: VladD2 Российская Империя www.nemerle.org
Дата: 30.01.09 15:29
Оценка:
Здравствуйте, Константин Л., Вы писали:

КЛ>1. Итак, ничего страшного получить мы не должны

КЛ>2. Если под конструктором тут понимается конструктор объекта, тот тут опять нет ничего такого, что подтверждает вашу теорию.

Елы-палы. Фраза "CLI совершенно не обязана гарантировать, что все изменение состояния, происходящие в конструкторе, должны быть одинаково видны пока конструктор не отработает" не отвергает того факта, что по окончанию работы конструктора состояние объекта должно быть одинаково видно всем кому дали ссылку на него.

КЛ>В общем, ничего существенного этот абзац нам не дает.


Вот именно. В том смысле, что она тут просто не к месту. Оно о другом.

Есть четкий порядок создания объекта:
1. Выделение памяти.
2. Работа конструктора.
3. Присвоение ссылки переменной.

Дотнет гарантирует, что ссылка присваивается только на сформированный объект.
Что до кэшей процессоров, то если они будут разными, то потребуется сбрасывать их при обращении к любому разеляемому объекту. Это сделает неверным половину кода в библиотеках донтета.
Ну, а переписывание таких объемов кода уже и правда паранойя.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[17]: Потокобезопасность инициализации Comparer<T>.Default
От: VladD2 Российская Империя www.nemerle.org
Дата: 30.01.09 15:35
Оценка:
Здравствуйте, nikov, Вы писали:

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


А что он читать то будет? Откуда у него кэш взялся? Он же к этой области памяти еще не обращался. Если же у него есть кэш, то он и нули может не увидеть.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[16]: перевод
От: WolfHound  
Дата: 30.01.09 15:42
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Дотнет гарантирует, что ссылка присваивается только на сформированный объект.

Но не гарантирует что второй поток увидит сформированный объект раньше чем ссылку на него.

VD>Что до кэшей процессоров, то если они будут разными, то потребуется сбрасывать их при обращении к любому разеляемому объекту. Это сделает неверным половину кода в библиотеках донтета.

Половину говоришь?
Ну тогда тебе не составит труда показать где еще в .NET'те есть race condition'ы.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[23]: Потокобезопасность инициализации Comparer<T>.Default
От: VladD2 Российская Империя www.nemerle.org
Дата: 30.01.09 15:55
Оценка:
Здравствуйте, nikov, Вы писали:

КЛ>>Кароче, это что-то из ряда фантастики. Как тогда проги писать, простите?

N>Далеко не все проги многопоточные. А многопоточные используют синхронизацию или вообще высокоуровневые феймворки, в которых уже все продумано и протестировано.

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

Если это так, то как дотнет можно использовать для создания многопоточных приложений?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[23]: Потокобезопасность инициализации Comparer<T>.Default
От: VladD2 Российская Империя www.nemerle.org
Дата: 30.01.09 16:00
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Если бы там стоял lock вопросов бы небыло.


Только на запись? Глупо как-то. А на чтение — это будет полный кабздец с производительностью.

WH>А тут народ вобще попытался wait free сделать.


Предлагаешь не пользоваться реализацией МС?

WH>Так что если занялся особой многопоточной магией изучи как она работает.


Мне кажется, что этот диспут увел от основной темы.

Что у нас со switch и 2-3-деревом?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[24]: Потокобезопасность инициализации Comparer<T>.Default
От: VladD2 Российская Империя www.nemerle.org
Дата: 30.01.09 16:02
Оценка:
Здравствуйте, Константин Л., Вы писали:

КЛ>С такой что, это, как минимум, логично и не просаживает перфоманс. Как ты думаешь, что бы было, если бы значение ссылки и то, на что она указывает хотя бы в половине случаев не лежало в одном кеше или в одной линейке кеша?


Не думаю, что производительность как-то изменилась бы если после вызова конструктора и перед присвоением ссылки полю был бы вызов Thread.MemoryBarrier().
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[17]: перевод
От: Константин Л. Франция  
Дата: 30.01.09 16:03
Оценка:
Здравствуйте, WolfHound, Вы писали:

[]

System.Collections.Generic.EqualityComparer<T>.Default
Re[24]: Потокобезопасность инициализации Comparer<T>.Default
От: WolfHound  
Дата: 30.01.09 16:03
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Исходя из ваших рассуждений все коллекции использующие компараторы или им подобные объекты (т.е. просто все коллекции фрэймворка) не являются потокобезопасными в принципе.

Так и есть.
Починить это можно расстановкой барьеров памяти или lock'а.

VD>Если это так, то как дотнет можно использовать для создания многопоточных приложений?

Похоже что нельзя.
Правда окно в котором эта проблема может проявиться очень маленькое.
Также возможно что некоторые особенности текущей реализации не дают этой проблеме проявится.
Но стандарт не гарантирует что этого не случится в некоторых других реализациях.
Например под другой процессор.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[25]: Потокобезопасность инициализации Comparer<T>.Default
От: Константин Л. Франция  
Дата: 30.01.09 16:04
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, Константин Л., Вы писали:


КЛ>>С такой что, это, как минимум, логично и не просаживает перфоманс. Как ты думаешь, что бы было, если бы значение ссылки и то, на что она указывает хотя бы в половине случаев не лежало в одном кеше или в одной линейке кеша?


VD>Не думаю, что производительность как-то изменилась бы если после вызова конструктора и перед присвоением ссылки полю был бы вызов Thread.MemoryBarrier().


Я не про это. Я про ситуацию, когда ссылка и память не лежат рядом в кеше.
Re[25]: Потокобезопасность инициализации Comparer<T>.Default
От: Константин Л. Франция  
Дата: 30.01.09 16:06
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Здравствуйте, VladD2, Вы писали:


VD>>Исходя из ваших рассуждений все коллекции использующие компараторы или им подобные объекты (т.е. просто все коллекции фрэймворка) не являются потокобезопасными в принципе.

WH>Так и есть.
WH>Починить это можно расстановкой барьеров памяти или lock'а.

VD>>Если это так, то как дотнет можно использовать для создания многопоточных приложений?

WH>Похоже что нельзя.
WH>Правда окно в котором эта проблема может проявиться очень маленькое.
WH>Также возможно что некоторые особенности текущей реализации не дают этой проблеме проявится.
WH>Но стандарт не гарантирует что этого не случится в некоторых других реализациях.
WH>Например под другой процессор.

Андрей, какой стандарт? Ссылку плиз на пункт
Re[17]: перевод
От: VladD2 Российская Империя www.nemerle.org
Дата: 30.01.09 16:07
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Здравствуйте, VladD2, Вы писали:


VD>>Дотнет гарантирует, что ссылка присваивается только на сформированный объект.

WH>Но не гарантирует что второй поток увидит сформированный объект раньше чем ссылку на него.

А откуда возмещается кэш то на эту область памяти?

VD>>Что до кэшей процессоров, то если они будут разными, то потребуется сбрасывать их при обращении к любому разеляемому объекту. Это сделает неверным половину кода в библиотеках донтета.

WH>Половину говоришь?
WH>Ну тогда тебе не составит труда показать где еще в .NET'те есть race condition'ы.

А зачем еще? Этот компаратор используется в половине коллекций. В другой половине коллекций используется System.Collections.Generic.EqualityComparer<T> в котором поле faultComparer инициализируется точно так же.

Можно конечно рассуждать как Ников. Типа конкретная реализация — донет гарантирует работоспособность этого кода, а в Моно сам EqualityComparer<T> может быть написан по другому. Но при этом опять же мы наблюдаем битву с ветряными мельницами.
В противном же случае гонки будут в любом коде использующем стандартные коллекции.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[25]: Потокобезопасность инициализации Comparer<T>.Default
От: VladD2 Российская Империя www.nemerle.org
Дата: 30.01.09 16:11
Оценка:
Здравствуйте, WolfHound, Вы писали:

VD>>Если это так, то как дотнет можно использовать для создания многопоточных приложений?

WH>Похоже что нельзя.

Но это чушь, так как вот этот самый сервер держит по 200 параллельных клиентов и ни разу (вороде) не упал от null-ref-исключения по этому поводу.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[25]: Потокобезопасность инициализации Comparer<T>.Default
От: VladD2 Российская Империя www.nemerle.org
Дата: 30.01.09 16:13
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Также возможно что некоторые особенности текущей реализации не дают этой проблеме проявится.


Ну, а что ты тогда в исходники Comparer и EqualityComparer смотришь? Пусть те кто делает другой рантайм и заботятся о реализации этих классов.

WH>Но стандарт не гарантирует что этого не случится в некоторых других реализациях.

WH>Например под другой процессор.

Стандарт гарантирует, что я могу пользоваться коллекциями основанными на компараторе в разных потоках.
Так что или мы говорим о очень тонком и хорошо завуалированном баге дотнета, или вы действительно перебарщиваете с паранойей.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[26]: Потокобезопасность инициализации Comparer<T>.Default
От: VladD2 Российская Империя www.nemerle.org
Дата: 30.01.09 16:14
Оценка: +1
Здравствуйте, Константин Л., Вы писали:

VD>>Не думаю, что производительность как-то изменилась бы если после вызова конструктора и перед присвоением ссылки полю был бы вызов Thread.MemoryBarrier().


КЛ>Я не про это. Я про ситуацию, когда ссылка и память не лежат рядом в кеше.


А почему они должны лежать рядом? Это никто гарантировать не может.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[27]: Потокобезопасность инициализации Comparer<T>.Default
От: Константин Л. Франция  
Дата: 30.01.09 16:28
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, Константин Л., Вы писали:


VD>>>Не думаю, что производительность как-то изменилась бы если после вызова конструктора и перед присвоением ссылки полю был бы вызов Thread.MemoryBarrier().


КЛ>>Я не про это. Я про ситуацию, когда ссылка и память не лежат рядом в кеше.


VD>А почему они должны лежать рядом? Это никто гарантировать не может.


Я не про то что должны, а про то что это было бы логично и эффективно
Re[26]: Потокобезопасность инициализации Comparer<T>.Default
От: WolfHound  
Дата: 30.01.09 17:05
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Но это чушь, так как вот этот самый сервер держит по 200 параллельных клиентов и ни разу (вороде) не упал от null-ref-исключения по этому поводу.

Из-за этого можно упасть только на взлете.
После того как сервер прогрелся из-за этого уже не упасть.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[27]: Потокобезопасность инициализации Comparer<T>.Default
От: Константин Л. Франция  
Дата: 30.01.09 17:10
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Здравствуйте, VladD2, Вы писали:


VD>>Но это чушь, так как вот этот самый сервер держит по 200 параллельных клиентов и ни разу (вороде) не упал от null-ref-исключения по этому поводу.

WH>Из-за этого можно упасть только на взлете.
WH>После того как сервер прогрелся из-за этого уже не упасть.

Всё новые и новые знания ты нам открываешь. Источник бы...
Re[26]: Потокобезопасность инициализации Comparer<T>.Default
От: WolfHound  
Дата: 30.01.09 17:45
Оценка:
Здравствуйте, VladD2, Вы писали:

WH>>Также возможно что некоторые особенности текущей реализации не дают этой проблеме проявится.

VD>Ну, а что ты тогда в исходники Comparer и EqualityComparer смотришь? Пусть те кто делает другой рантайм и заботятся о реализации этих классов.
Так если реализацию рантайма изменят то может и всплыть.

VD>Так что или мы говорим о очень тонком и хорошо завуалированном баге дотнета, или вы действительно перебарщиваете с паранойей.

Если подходить с точки зрения стандарта то первое.
Если текущая реализация дает более сильные гарантии чем стребует стандарт то второе. Но это весьма зыбко ибо гарантии могут и ослабить до реальных требований стандарта.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[27]: Потокобезопасность инициализации Comparer<T>.Default
От: Константин Л. Франция  
Дата: 30.01.09 17:46
Оценка:
Здравствуйте, WolfHound, Вы писали:

[]

VD>>Так что или мы говорим о очень тонком и хорошо завуалированном баге дотнета, или вы действительно перебарщиваете с паранойей.

WH>Если подходить с точки зрения стандарта то первое.
WH>Если текущая реализация дает более сильные гарантии чем стребует стандарт то второе. Но это весьма зыбко ибо гарантии могут и ослабить до реальных требований стандарта.

Еще раз повторяю, где ссылка на стандарт?
Re[27]: Потокобезопасность инициализации Comparer<T>.Default
От: VladD2 Российская Империя www.nemerle.org
Дата: 30.01.09 19:21
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Из-за этого можно упасть только на взлете.

WH>После того как сервер прогрелся из-за этого уже не упасть.

Вот хоть бы раз хоть одно приложение упало бы на взлете из-за проблем с потоками и коллекциями...
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[28]: Потокобезопасность инициализации Comparer<T>.Default
От: nikov США http://www.linkedin.com/in/nikov
Дата: 30.01.09 20:26
Оценка: +1
Здравствуйте, VladD2, Вы писали:

WH>>Из-за этого можно упасть только на взлете.

WH>>После того как сервер прогрелся из-за этого уже не упасть.

VD>Вот хоть бы раз хоть одно приложение упало бы на взлете из-за проблем с потоками и коллекциями...


Ну говорю же: в реальной жизни такого не бывает, потому что текущая реализация MS работает надежнее. Об этом даже Рихтер писал.
Re: Потокобезопасность инициализации Comparer<T>.Default
От: vdimas Россия  
Дата: 02.02.09 10:19
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>За тем что второй поток может увидеть указатель на компатор до того как тело компатора приедит к нему.

WH>Для того чтобы гарантировать что второй поток полностью увидит тело компатора нужен барьер памяти.

Перемудрил.
Это если бы два потока до этого обращались к области памяти _создаваемого_ объекта, то был бы прав, а так это практически невозможно.
Re[6]: Потокобезопасность инициализации Comparer<T>.Default
От: mrTwister Россия  
Дата: 02.02.09 10:21
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Слушай кончай антазировать. Нет там никаких проблем. Копирование ссылки — атомарная операция. Объект сначала формируется, а потом ссылка на него помещается в переменную. Неинициализированного объекта никто не увидит. Самое страшное, что случится — это могут создаться несколько копий компораторов, но так как они все равно будут идентичны, то по фигу кто какую копию будет использовать. Итого проблем тут быть не может.


Несмотря на то, что оно работает, никто не дает гарантий, что оно и дальше будет работать. Просто в текущей реализации все операции записи в .NET volatile (по крайней мере на x86). А по теории надо надо явно обозначать это, где надо.
лэт ми спик фром май харт
Re[3]: Потокобезопасность инициализации Comparer<T>.Default
От: vdimas Россия  
Дата: 02.02.09 10:24
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Здравствуйте, VladD2, Вы писали:


VD>>Я не вижу тут проблем:

WH>хъ
VD>>Comparer<T>.defaultComparer присваивается в самом конце когда компаратор уже сформирован.
WH>Следи за рукам: Есть 2 разных куска памяти.
WH>Первый содержит сам компатор. Второй содержит ссылку на компатор.
WH>Если второй поток сначала получит второй кусок памяти и не получит первый (на некоторых архитектурах такое возможно) получим чтение не пойми чего и как следствие не пойми какие последствия.

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

WH>Если вставить барьер памяти то второй поток гарантировано увидит первый кусок памяти раньше чем второй.


И так гарантированно, ибо только через разыменование.
Re[8]: Потокобезопасность инициализации Comparer<T>.Default
От: mrTwister Россия  
Дата: 02.02.09 10:24
Оценка:
Здравствуйте, Константин Л., Вы писали:

КЛ>1. Выделяется память

КЛ>2. На ней зовется ctor
КЛ>3. Ссылка на память присваивается переменной

КЛ>Вы патаетесь сказать, что порядок может быть 1,3,2? Какой в этом смысл?


Нет, ссылка присваивается переменной, а тот участок памяти, куда указывает ссылка, на другом процессоре ещё старый (процессорный кэш не успел обновиться).
лэт ми спик фром май харт
Re[9]: Потокобезопасность инициализации Comparer<T>.Default
От: Константин Л. Франция  
Дата: 02.02.09 10:35
Оценка:
Здравствуйте, mrTwister, Вы писали:

T>Здравствуйте, Константин Л., Вы писали:


КЛ>>1. Выделяется память

КЛ>>2. На ней зовется ctor
КЛ>>3. Ссылка на память присваивается переменной

КЛ>>Вы патаетесь сказать, что порядок может быть 1,3,2? Какой в этом смысл?


T>Нет, ссылка присваивается переменной, а тот участок памяти, куда указывает ссылка, на другом процессоре ещё старый (процессорный кэш не успел обновиться).


Это все лирика и к FW никакого отношения не имеет. Уже 10 раз прошу показать ссылку на стандарт, где написано, что такая ситуация возможна.
Re[28]: Потокобезопасность инициализации Comparer<T>.Default
От: mrTwister Россия  
Дата: 02.02.09 10:39
Оценка:
Здравствуйте, Константин Л., Вы писали:

КЛ>Всё новые и новые знания ты нам открываешь. Источник бы...


Ну, например, Рихтер об этом пишет.
лэт ми спик фром май харт
Re[10]: Потокобезопасность инициализации Comparer<T>.Default
От: mrTwister Россия  
Дата: 02.02.09 10:55
Оценка:
Здравствуйте, Константин Л., Вы писали:

КЛ>Это все лирика и к FW никакого отношения не имеет. Уже 10 раз прошу показать ссылку на стандарт, где написано, что такая ситуация возможна.


В стандарте ни слова не сказано, что FW обязан сбрасывать кэш на всех процессорах после каждой операции записи на любом из процессоров. Следовательно, не обязан. Именно для этого введено слово volatile — оно помечает переменные, обращение к которым автоматически сбрасывает кэши. Шутка в том, что в текущей реализации FW все переменные работают, как volatile.
лэт ми спик фром май харт
Re[11]: Потокобезопасность инициализации Comparer<T>.Default
От: Константин Л. Франция  
Дата: 02.02.09 11:15
Оценка:
Здравствуйте, mrTwister, Вы писали:

T>Здравствуйте, Константин Л., Вы писали:


КЛ>>Это все лирика и к FW никакого отношения не имеет. Уже 10 раз прошу показать ссылку на стандарт, где написано, что такая ситуация возможна.


T>В стандарте ни слова не сказано, что FW обязан сбрасывать кэш на всех процессорах после каждой операции записи на любом из процессоров. Следовательно, не обязан. Именно для этого введено слово volatile — оно помечает переменные, обращение к которым автоматически сбрасывает кэши. Шутка в том, что в текущей реализации FW все переменные работают, как volatile.


Не надо только путать сбрасывание кешей, volatile и такую ситуацию, которую мы рассматриваем. Кстати, если Рихтер пишет, то ссылку плиз.
Re[18]: Потокобезопасность инициализации Comparer<T>.Default
От: nikov США http://www.linkedin.com/in/nikov
Дата: 02.02.09 13:07
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>А что он читать то будет? Откуда у него кэш взялся? Он же к этой области памяти еще не обращался. Если же у него есть кэш, то он и нули может не увидеть.


Да мало ли какой код мог в этом потоке работать... Может быть, эта память читалась с помощью unsafe кода (например, в приложении есть memory viewer).
Re[18]: Потокобезопасность инициализации Comparer<T>.Default
От: nikov США http://www.linkedin.com/in/nikov
Дата: 02.02.09 16:27
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>А что он читать то будет? Откуда у него кэш взялся? Он же к этой области памяти еще не обращался. Если же у него есть кэш, то он и нули может не увидеть.


Еще, например, GC-поток мог работать на этом же процессоре.
Re[19]: Потокобезопасность инициализации Comparer<T>.Default
От: Sinix  
Дата: 04.02.09 08:05
Оценка:
9 страниц переспрашивания... Не надоело?

Когда читал у Рихтера — отложилось в памяти так:

Многопоточное обращение к инициализируемой переменной может привести к получению ссылки на забитую нулями область памяти из-за того что ссылка уже проинициализирована и сброшена из кэша в память, а _сам_ объект ещё нет.

Вероятность такого события крайне мала и определяется архитектурой процессора/неоднородностью памяти/моделью синхронизации кэша и памяти/порядком выполнения команд и т.п. Классический пример — intel itanium, который допускает частичяное переупорядочивание команд записи. Чтобы такой ситуации не возникало следует перед обращением к переменной сфлушить кеш в память — тот самый memory barrier что гарантирует последовательность операций с памятью (т.е. что запись произойдёт _до_ чтения). В дотнете это сделано из коробки, но поскольку такое поведение не гарантируется стандартом (в bcl team блоге по
этому поводу сокрушались ещё в 2к4-м), будьте любезны озаботиться синхронизацией явно. В чём проблемы???

P.S. если бы сделали static readonly defaultComparer = new Comparer<T>(); + cctor чтобы получить beforefieldinit на поле — разговаривать было бы не о чем — JIT сам добавил бы лок.

Как дети малые — почему, почему... матчасть учить надо...
Re[20]: Потокобезопасность инициализации Comparer<T>.Default
От: Константин Л. Франция  
Дата: 04.02.09 08:57
Оценка:
Здравствуйте, Sinix, Вы писали:

S>9 страниц переспрашивания... Не надоело?


нет, тк без пруфлинка это всего-лишь слова

S>Когда читал у Рихтера — отложилось в памяти так:


S>Многопоточное обращение к инициализируемой переменной может привести к получению ссылки на забитую нулями область памяти из-за того что ссылка уже проинициализирована и сброшена из кэша в память, а _сам_ объект ещё нет.


S>Вероятность такого события крайне мала и определяется архитектурой процессора/неоднородностью памяти/моделью синхронизации кэша и памяти/порядком выполнения команд и т.п. Классический пример — intel itanium, который допускает частичяное переупорядочивание команд записи. Чтобы такой ситуации не возникало следует перед обращением к переменной сфлушить кеш в память — тот самый memory barrier что гарантирует последовательность операций с памятью (т.е. что запись произойдёт _до_ чтения). В дотнете это сделано из коробки, но поскольку такое поведение не гарантируется стандартом (в bcl team блоге по

S>этому поводу сокрушались ещё в 2к4-м), будьте любезны озаботиться синхронизацией явно. В чём проблемы???

Проблемы в том, что это все в общем относится к самой платформе, но не к FW. Мне все-лишь нужно место в стандарте, где описывается не такое поведение на какой-то платформе, а такое поведение FW на какой-то платформе. У нас тут не с++.

S>P.S. если бы сделали static readonly defaultComparer = new Comparer<T>(); + cctor чтобы получить beforefieldinit на поле — разговаривать было бы не о чем — JIT сам добавил бы лок.


S>Как дети малые — почему, почему... матчасть учить надо...


предлагаю заняться тем же
Re[21]: Потокобезопасность инициализации Comparer<T>.Default
От: Sinix  
Дата: 04.02.09 09:10
Оценка:
Здравствуйте, Константин Л.

S>>9 страниц переспрашивания... Не надоело?

КЛ>нет, тк без пруфлинка это всего-лишь слова

Ecma 335 вам цитатили вроде. Рихтера щас не полистаю — дома он. Но так оно, так — поверьте Погуглите по сочетанию "clr itanium memory barrier volatile". Скорее всего найдётся.

КЛ>Проблемы в том, что это все в общем относится к самой платформе, но не к FW. Мне все-лишь нужно место в стандарте, где описывается не такое поведение на какой-то платформе, а такое поведение FW на какой-то платформе. У нас тут не с++.


Оно относится к некоей гипотетической реализации рантайма на некоей гипотетической платформе. Проблема только в излишней мягкости стандарта. В реализации clr от МС (начиная с 2.0 насколько помню. А может и 1.1.сп1... но вряд ли.) это решается из коробки volatile-по-умолчанию полями.

S>>Как дети малые — почему, почему... матчасть учить надо...

КЛ>предлагаю заняться тем же

Дык всё время...
Re[22]: Потокобезопасность инициализации Comparer<T>.Default
От: Константин Л. Франция  
Дата: 04.02.09 09:27
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Здравствуйте, Константин Л.


S>>>9 страниц переспрашивания... Не надоело?

КЛ>>нет, тк без пруфлинка это всего-лишь слова

S>Ecma 335 вам цитатили вроде. Рихтера щас не полистаю — дома он. Но так оно, так — поверьте Погуглите по сочетанию "clr itanium memory barrier volatile". Скорее всего найдётся.


То, что цитировали к делу не имеет никакого отношения. Так, общие слова, не более. Че-та не гуглится

КЛ>>Проблемы в том, что это все в общем относится к самой платформе, но не к FW. Мне все-лишь нужно место в стандарте, где описывается не такое поведение на какой-то платформе, а такое поведение FW на какой-то платформе. У нас тут не с++.


S>Оно относится к некоей гипотетической реализации рантайма на некоей гипотетической платформе. Проблема только в излишней мягкости стандарта. В реализации clr от МС (начиная с 2.0 насколько помню. А может и 1.1.сп1... но вряд ли.) это решается из коробки volatile-по-умолчанию полями.


[]
Re[28]: Потокобезопасность инициализации Comparer<T>.Default
От: Sinclair Россия https://github.com/evilguest/
Дата: 05.02.09 08:09
Оценка:
Здравствуйте, Константин Л., Вы писали:
КЛ>Я не про то что должны, а про то что это было бы логично и эффективно
Это было бы нелогично и неэффективно. На всякий случай напомню, что ссылка может быть в том числе и на массив, вполне произвольного размера. А кэш — не резиновый. У тебя запросто может быть цикл, (код которого естественно сам лежит в кэше), который бежит по массиву стрингов (который не обязан лежать рядом в с кодом в памяти) и с каждой строкой что-то делать, сканируя все ее символы.
С точки зрения кэша вполне нормально держать каждый из этих фрагментов в отдельной линейке — кэша вполне хватит на то, чтобы обеспечить 90-99% cache hit ratio в таких условиях. Несмотря на то, что суммарный объем строк сушественно превышает ёмкость кэша.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[29]: Потокобезопасность инициализации Comparer<T>.Default
От: Константин Л. Франция  
Дата: 05.02.09 10:20
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, Константин Л., Вы писали:

КЛ>>Я не про то что должны, а про то что это было бы логично и эффективно
S>Это было бы нелогично и неэффективно. На всякий случай напомню, что ссылка может быть в том числе и на массив, вполне произвольного размера. А кэш — не резиновый. У тебя запросто может быть цикл, (код которого естественно сам лежит в кэше), который бежит по массиву стрингов (который не обязан лежать рядом в с кодом в памяти) и с каждой строкой что-то делать, сканируя все ее символы.
S>С точки зрения кэша вполне нормально держать каждый из этих фрагментов в отдельной линейке — кэша вполне хватит на то, чтобы обеспечить 90-99% cache hit ratio в таких условиях. Несмотря на то, что суммарный объем строк сушественно превышает ёмкость кэша.

а теперь давай представим что это не массив.
Re[30]: Потокобезопасность инициализации Comparer<T>.Default
От: Sinclair Россия https://github.com/evilguest/
Дата: 05.02.09 10:54
Оценка:
Здравствуйте, Константин Л., Вы писали:
КЛ>а теперь давай представим что это не массив.
И? Положение объекта в кэше определяется его расположением в памяти. Расположение в памяти определяется (в дотнете) порядком создания объектов. Память под ссылку в данном случае выделяется при инициализации класса, т.е. в момент загрузки сборки. Память под объект выделяется в момент первого обращения — за это время указатель на вершину хипа убежал черти куда. Поэтому шансов на то, что ссылка будет прямо рядом с данными, на которые она показывает, очень мало. Это в данном контексте. То бишь, пытаться сделать наоборот было бы нелогично и неэффективно.

То, о чем ты говоришь, может иметь место только в случаях специальных структур данных. Например, связных списков или деревьев — там, в случае быстрых массовых модификаций, есть шансы более-менее плотно занять память.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[6]: Потокобезопасность инициализации Comparer<T>.Default
От: remark Россия http://www.1024cores.net/
Дата: 18.02.09 20:56
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Слушай кончай антазировать. Нет там никаких проблем. Копирование ссылки — атомарная операция. Объект сначала формируется, а потом ссылка на него помещается в переменную. Неинициализированного объекта никто не увидит.


Атомарность тут совсем ни при чём. Тебе говорят про относительное упорядочивание обращений к памяти.
Если ты опускаешься ниже "каждый доступ защищён мьютексом", то действительно должен перестать думать последовательно, sequential consistency сейчас уже никто в здравом уме не предоставляет. Это значит, что ты должен перестать думать "это происходит до этого, значит то происходит перед вот этим", по крайней мере основываясь на программном порядке — программный порядок НЕ соблюдается в многопоточном окружении!
Что такое модель памяти? И с чем её едят?
Автор: remark
Дата: 20.11.08



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.