Работа с потоками в C#. Часть 1.
От: Алексей Кирюшкин (перевод) Россия http://malgarr.blogspot.com/
Дата: 24.04.07 14:55
Оценка: 1111 (45) +3
Статья:
Работа с потоками в C#. Часть 1.
Автор(ы): Joseph Albahari
Дата: 24.03.2007
Подробно рассматривается работа с потоками — запуск, завершение, прерывание, блокировки, синхронизация, контексты синхронизации, особенности взаимодействия с апартаментами, а также потоковые возможности .NET — потоковые таймеры, пулы потоков, BackgroundWorker, асинхронные методы и делегаты.
В статье использован материал из книги Joseph Albahari, Ben Albahari "C# 3.0 in a Nutshell" — http://www.oreilly.com/catalog/9780596527570/


Авторы:
Алексей Кирюшкин (перевод)

Аннотация:
В первой части статьи рассматриваются основы работы с потоками — запуск, завершение, прерывание, блокировки и базовые сведения о синхронизации.
В статье использован материал из книги Joseph Albahari, Ben Albahari "C# 3.0 in a Nutshell" — http://www.oreilly.com/catalog/9780596527570/
Re[3]: Работа с потоками в C#. Часть 1.
От: _FRED_ Черногория
Дата: 31.05.07 08:51
Оценка: 23 (4) +5
Здравствуйте, Dog, Вы писали:

АКП>>>Статья:

АКП>>>Работа с потоками в C#. Часть 1.
Автор(ы): Joseph Albahari
Дата: 24.03.2007
Подробно рассматривается работа с потоками — запуск, завершение, прерывание, блокировки, синхронизация, контексты синхронизации, особенности взаимодействия с апартаментами, а также потоковые возможности .NET — потоковые таймеры, пулы потоков, BackgroundWorker, асинхронные методы и делегаты.
В статье использован материал из книги Joseph Albahari, Ben Albahari "C# 3.0 in a Nutshell" — http://www.oreilly.com/catalog/9780596527570/

_FR>>Огорчает нежелание (непонимание ) автора использовать модификатор readonly в объявлении "объекта синхронизации".
Dog>Ну так и написали бы почему необходимо использовать...

Не то, что бы необходимо, но, ИМХО, GoodPractice. Значение "объекту синхронизации" присваивается при объявлении:
object syncRoot = new object();

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

А раз переприсваивать значение не нужно и даже опасно, то не надо:
  • ни рассчитывать на разумность людей, которые будут, возможно, пользоваться вашим кодом;
  • ни предупреждать, например, в комментариях, что нельзя перезаписывать значение вот этой вот переменной,
    когда можно попросту это запретить:
    readonly object syncRoot = new object();

    Теперь, даже если кому-то случайно\по незнанию захочется что-то своё записать в это поле, он узнает, что так делать нельзя.

    После знакомства с последними тенденциями (Linq, Nemerle), я процентов 90 полей объявляю как readonly, ибо позволяет избежать множества проблем, самая первая из которых "не null ли в этом поле"? Во-вторых, класс, содержащий только readonly поля автоматически становится потокобезопасным. Есть и много других (большей частью эстетических) плюсов. Общее правило такое: не объявлять поле как НЕ readonly только если его ну никак нельзя сделать readonly.

    Да, я знаю, что в Framework Design Guidelines сказано, что этот модификатор рекомендуется использовать только с immutable-типами, но не согласен: модификотором readonly я защищаю не столько "содержимое", "данные" объекта, сколько ссылку на него. В C++ аналогом readonly я бы назвал
    T* const field; //константный указатель
    , в то время как многим хочется видеть
    const T* field; //указатель на константу
  • Help will always be given at Hogwarts to those who ask for it.
    Re[7]: Работа с потоками в C#. Часть 1.
    От: Sinclair Россия https://github.com/evilguest/
    Дата: 31.05.07 10:18
    Оценка: 25 (5)
    Здравствуйте, rsn81, Вы писали:

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


    _FR>>Грабли в этом переприсвоении читателю предлагается найти самому ;о)

    R>Я глупый, объясните мне, что плохого?
    R>Намекаете, что при выходе из lock блокировка с "потерянного" объекта не снимется? Не верю, а MSVS нет под рукой проверить... Это точно так?
    Это точно не так.
    Но зато сразу после переприсвоения, еще до отпускания старого лока, другой поток сможет легко войти в защищенную lock-ом зону, т.к. будет блокироваться на другом объекте.
    ... << RSDN@Home 1.2.0 alpha rev. 677>>
    Уйдемте отсюда, Румата! У вас слишком богатые погреба.
    Re[4]: Работа с потоками в C#. Часть 1.
    От: Mika Soukhov Stock#
    Дата: 31.05.07 08:50
    Оценка: +3
    Здравствуйте, Lloyd, Вы писали:

    L>Здравствуйте, Mika Soukhov, Вы писали:


    MS>>Присваиваение и считывание — одна операция. Только вот x++ это не одна операция, а целых три.


    L>Думаю, .Den неспроста выделил пример с присваиванием.


    Если убрать лок у присваивания, то будет возможно ситуация, что между инкрементированием х он станет равным 123. Задача конечно надумана (лично по мне, ну и что, что будет 123), но видимо автор и хотел донести, что или присваивать или инкрементировать.

    Сейчас решил прочитать статью (вернее тот участок ), и увидел вот это

    Как правило, любое поле, доступное нескольким потокам, должно читаться и записываться с блокировкой. Даже в самом простом случае, операции присваивания одиночному полю, необходима синхронизация. В следующем классе ни приращение, ни присваивание не потокобезопасны:


    Выделенное — неправильно. Но на удивление, сам пример корректен.
    Re[5]: Работа с потоками в C#. Часть 1.
    От: Mika Soukhov Stock#
    Дата: 31.05.07 09:30
    Оценка: +3
    Здравствуйте, rsn81, Вы писали:

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


    R>Если резюмировать: безопасность инициализации по умолчанию является потоковой — и это может жестко обеспечить readonly. Так, например, в Java тоже делает final.


    R>Может быть неправ (по-крайнем мере в Java это так), но мне кажется в примерах в принципе все корректно. Объект синхронизации является статическим полем, а соответственно инициализируется при первом обращении к нему, то есть как раз когда происходит инициализация класса. Соответственно, потоковая безопасность инициализации и здесь действует.


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

    [Филосовствуя] Вообще, нужно было сразу делать поля неизменяемыми. И, если они должны изменятся, нужно явно помечать поле как mutable.
    Re[6]: Работа с потоками в C#. Часть 1.
    От: rsn81 Россия http://rsn81.wordpress.com
    Дата: 31.05.07 09:37
    Оценка: 1 (1)
    Здравствуйте, Mika Soukhov, Вы писали:

    Я имел в виду, что final в Java не просто immutable-модификатор, но еще и играет роль в потоковой безопасности. Подозреваю, что в C# работает с readonly аналогично. Если не прав, пните.

    Безопасность инициализации

    Новая модель памяти JMM также старается предоставить новые гарантии безопасности инициализации. То есть, если объект соответствующим образом сконструирован (то есть ссылка на объект не опубликована, пока конструирование не завершено), тогда все потоки будут видеть значения его полей final, которые были установлены конструктором, независимо от того, используется ли синхронизация, чтобы передать ссылку из одного потока другому. Более того, переменные, которые могут быть доступны через поле final должным образом сконструированного объекта, например поля объекта, на который ссылается поле final, также гарантированно видимы другим потокам. Это значит, что если поле final содержит ссылку на, скажем, LinkedList, кроме видимости правильного значения ссылки другим потокам, содержимое этого LinkedList во время конструирования будет доступно другим потокам без синхронизации. Результат этого — значительное усиление значения final, то есть поля final могут быть безопасно доступны без синхронизации, и компиляторы могут предположить, что поля final не изменятся, и следовательно смогут оптимизировать множественные выборки.

    Final значит final

    Механизм, по которому поля final могли менять свое значение под старой моделью памяти был описан в Части 1 — в отсутствии синхронизации другой поток мог сначала видеть значение по умолчанию для поля final, а позже видеть правильное значение.

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

    (c) Брайан Гетц, Теория и практика Java: Исправление модели памяти Java, часть 2

    По поводу статической инициализации в той же статье:

    Вместо блокировки с двойной проверкой используйте идиому Initialize-on-demand Holder Class, которая обеспечивает ленивую инициализацию, потокобезопасность, и работает быстрее и не так запутанно как блокировка с двойной проверкой:

    Листинг 2. Идиома Initialize-On-Demand Holder Class

    private static class LazySomethingHolder {
      public static Something something = new Something();
    }
    
    ...
    
    public static Something getInstance() {
      return LazySomethingHolder.something;
    }

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

    ... << RSDN@Home 1.2.0 alpha rev. 677>>
    Re[8]: Работа с потоками в C#. Часть 1.
    От: Максим Зелинский  
    Дата: 31.05.07 09:51
    Оценка: +1
    Здравствуйте, tol05, Вы писали:

    T>Здравствуйте, Mika Soukhov, Вы писали:


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


    T>Хочу спросить: ведь Ваше высказывание справедливо только для однопроцессорных систем? Рихтер в своей книге писал, что для многопроцессорных систем из-за наличия кеширования данных процессорами могут возникнуть проблемы, особенно при записи. Поэтому он рекомендует запись обязательно синхронизировать, а чтение — на усмотрение. Какое Ваше мнение по этому поводу?

    Не смешивайте. Проблемы с кэшем решаются через volitale и ему подобные конструкции, а блокировать ли на чтение, это уже другой вопрос, не имеющий отношение к кэшу.
    ... << RSDN@Home 1.2.0 alpha rev. 679>>
    Re[9]: Работа с потоками в C#. Часть 1.
    От: Максим Зелинский  
    Дата: 31.05.07 09:58
    Оценка: +1
    Здравствуйте, rsn81, Вы писали:

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


    R>Атомарность операции и означает, что после ее выполнения данные будут доступны всем потокам, т.е. не будут находиться в регистрах, локальном кэше процессора и т.п.

    Разве? Всегда считал, что атомарность значит "нераздельно". В плане команд это значит, что атомарную инструкцию будет выполнять всегда один поток. Просто если операция обернута в lock, то тогда да, данные будут сбрасываться
    ... << RSDN@Home 1.2.0 alpha rev. 679>>
    Re[10]: Работа с потоками в C#. Часть 1.
    От: Mika Soukhov Stock#
    Дата: 31.05.07 10:06
    Оценка: +1
    Здравствуйте, Максим Зелинский, Вы писали:

    МЗ>Разве? Всегда считал, что атомарность значит "нераздельно". В плане команд это значит, что атомарную инструкцию будет выполнять всегда один поток.


    Вроде как все инструкции атомарны. Или ты про операции?
    Re[10]: Работа с потоками в C#. Часть 1.
    От: Mika Soukhov Stock#
    Дата: 31.05.07 12:16
    Оценка: +1
    Здравствуйте, tol05, Вы писали:

    T>Здравствуйте, Mika Soukhov, Вы писали:


    MS>>Я даже более могу сказать. В лок можно передавать объекты велью типов

    T>А в чем тогда смысл лока? Value типы не имеют индекса синхронизации, как же один поток узнает, что переменная заблокирована другим потоком?

    Не знаю, что такое индекс синхронизации у Value типа, но смысла тут и нет. Аргумент каждый раз боксится, и в лок передается новый объект. Вообщем, рассматривай это как bad (maybe worst) practic.
    Re[10]: Работа с потоками в C#. Часть 1.
    От: Lloyd Россия  
    Дата: 31.05.07 12:16
    Оценка: +1
    Здравствуйте, tol05, Вы писали:

    MS>>Я даже более могу сказать. В лок можно передавать объекты велью типов

    T>А в чем тогда смысл лока? Value типы не имеют индекса синхронизации,

    в незабоксеном состоянии

    T>как же один поток узнает, что переменная заблокирована другим потоком?
    ... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
    Re[8]: Работа с потоками в C#. Часть 1.
    От: FDSC Россия consp11.github.io блог
    Дата: 31.05.07 15:42
    Оценка: -1
    Здравствуйте, tol05, Вы писали:

    T>Здравствуйте, Mika Soukhov, Вы писали:


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


    T>Хочу спросить: ведь Ваше высказывание справедливо только для однопроцессорных систем? Рихтер в своей книге писал, что для многопроцессорных систем из-за наличия кеширования данных процессорами могут возникнуть проблемы, особенно при записи. Поэтому он рекомендует запись обязательно синхронизировать, а чтение — на усмотрение. Какое Ваше мнение по этому поводу?


    Кэши синхронизируются аппаратно независимо от локов программиста. Операция инкремента то же может быть вызвана без локов, если она осуществляется командой inc с префиском lock, который блокирует системную шину
    Re[9]: Работа с потоками в C#. Часть 1.
    От: torquemada  
    Дата: 01.06.07 10:39
    Оценка: :)
    Здравствуйте, rsn81, Вы писали:

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


    ie>>А кто это так умеет?

    R>Eclipse SDK 3.3 (source code cleanup refactoring).

    Извиняюсь за офтоп, но насколько мне известно, достойного C# плагина для eclipse не существует, по крайней мере я его не нашёл.
    ... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
    Re: Работа с потоками в C#. Часть 1.
    От: _FRED_ Черногория
    Дата: 30.05.07 15:05
    Оценка:
    Здравствуйте, Алексей Кирюшкин (перевод), Вы писали:

    АКП>Статья:

    АКП>Работа с потоками в C#. Часть 1.
    Автор(ы): Joseph Albahari
    Дата: 24.03.2007
    Подробно рассматривается работа с потоками — запуск, завершение, прерывание, блокировки, синхронизация, контексты синхронизации, особенности взаимодействия с апартаментами, а также потоковые возможности .NET — потоковые таймеры, пулы потоков, BackgroundWorker, асинхронные методы и делегаты.
    В статье использован материал из книги Joseph Albahari, Ben Albahari "C# 3.0 in a Nutshell" — http://www.oreilly.com/catalog/9780596527570/


    Огорчает нежелание (непонимание ) автора использовать модификатор readonly в объявлении "объекта синхронизации".
    Help will always be given at Hogwarts to those who ask for it.
    Re: Работа с потоками в C#. Часть 1.
    От: .Den Украина  
    Дата: 30.05.07 16:52
    Оценка:
    Здравствуйте, Алексей Кирюшкин (перевод), Вы писали:
    class ThreadUnsafe 
    {
      static object locker = new object();
      static int x;
     
      static void Increment()
      {
        lock (locker)
          x++;
      }
    
    
      static void Assign()
      {
        lock (locker)
          x = 123;
      }
    }

    Чо за бред?

    Из спецификации языка: 5.5 Atomicity of variable references
    Reads and writes of the following data types are atomic: bool, char, byte, sbyte, short, ushort, uint, int, float, and reference types.
    Re[2]: Работа с потоками в C#. Часть 1.
    От: Mika Soukhov Stock#
    Дата: 30.05.07 18:16
    Оценка:
    Здравствуйте, .Den, Вы писали:

    D>Чо за бред?


    D>Из спецификации языка: 5.5 Atomicity of variable references

    D>Reads and writes of the following data types are atomic: bool, char, byte, sbyte, short, ushort, uint, int, float, and reference types.

    Присваиваение и считывание — одна операция. Только вот x++ это не одна операция, а целых три.
    Re[2]: Работа с потоками в C#. Часть 1.
    От: Dog  
    Дата: 31.05.07 08:17
    Оценка:
    АКП>>Статья:
    АКП>>Работа с потоками в C#. Часть 1.
    Автор(ы): Joseph Albahari
    Дата: 24.03.2007
    Подробно рассматривается работа с потоками — запуск, завершение, прерывание, блокировки, синхронизация, контексты синхронизации, особенности взаимодействия с апартаментами, а также потоковые возможности .NET — потоковые таймеры, пулы потоков, BackgroundWorker, асинхронные методы и делегаты.
    В статье использован материал из книги Joseph Albahari, Ben Albahari "C# 3.0 in a Nutshell" — http://www.oreilly.com/catalog/9780596527570/

    _FR>Огорчает нежелание (непонимание ) автора использовать модификатор readonly в объявлении "объекта синхронизации".
    Ну так и написали бы почему необходимо использовать...
    ... << RSDN@Home 1.2.0 alpha rev. 669>>
    Re[3]: Работа с потоками в C#. Часть 1.
    От: Lloyd Россия  
    Дата: 31.05.07 08:37
    Оценка:
    Здравствуйте, Mika Soukhov, Вы писали:

    MS>Присваиваение и считывание — одна операция. Только вот x++ это не одна операция, а целых три.


    Думаю, .Den неспроста выделил пример с присваиванием.
    ... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
    Re[5]: Работа с потоками в C#. Часть 1.
    От: Lloyd Россия  
    Дата: 31.05.07 08:55
    Оценка:
    Здравствуйте, Mika Soukhov, Вы писали:

    L>>Думаю, .Den неспроста выделил пример с присваиванием.


    MS>Если убрать лок у присваивания, то будет возможно ситуация, что между инкрементированием х он станет равным 123. Задача конечно надумана (лично по мне, ну и что, что будет 123), но видимо автор и хотел донести, что или присваивать или инкрементировать.


    Да, действительно все правильно.
    ... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
    Re[5]: Работа с потоками в C#. Часть 1.
    От: andrey.bond  
    Дата: 31.05.07 09:08
    Оценка:
    Здравствуйте, Mika Soukhov, Вы писали:

    MS>Как правило, любое поле, доступное нескольким потокам, должно читаться и записываться с блокировкой. Даже в самом простом случае, операции присваивания одиночному полю, необходима синхронизация. В следующем классе ни приращение, ни присваивание не потокобезопасны:

    MS>[/q]

    MS>Выделенное — неправильно. Но на удивление, сам пример корректен.


    Почему?
    Re[6]: Работа с потоками в C#. Часть 1.
    От: Mika Soukhov Stock#
    Дата: 31.05.07 09:14
    Оценка:
    Здравствуйте, andrey.bond, Вы писали:

    AB>Здравствуйте, Mika Soukhov, Вы писали:


    MS>>Как правило, любое поле, доступное нескольким потокам, должно читаться и записываться с блокировкой. Даже в самом простом случае, операции присваивания одиночному полю, необходима синхронизация. В следующем классе ни приращение, ни присваивание не потокобезопасны:

    MS>>[/q]

    MS>>Выделенное — неправильно. Но на удивление, сам пример корректен.


    AB>Почему?


    Потому что, как было сказано выше, считывание и запись — атомарные операции. Блокировки нужно вводить, когда вводится третье действие — операция над данными, которое содержит поле.
    Re[4]: Работа с потоками в C#. Часть 1.
    От: rsn81 Россия http://rsn81.wordpress.com
    Дата: 31.05.07 09:24
    Оценка:
    Здравствуйте, _FRED_, Вы писали:

    Если резюмировать: безопасность инициализации по умолчанию является потоковой — и это может жестко обеспечить readonly. Так, например, в Java тоже делает final.

    Может быть неправ (по-крайнем мере в Java это так), но мне кажется в примерах в принципе все корректно. Объект синхронизации является статическим полем, а соответственно инициализируется при первом обращении к нему, то есть как раз когда происходит инициализация класса. Соответственно, потоковая безопасность инициализации и здесь действует.
    ... << RSDN@Home 1.2.0 alpha rev. 677>>
    Re[7]: Работа с потоками в C#. Часть 1.
    От: tol05  
    Дата: 31.05.07 09:43
    Оценка:
    Здравствуйте, Mika Soukhov, Вы писали:

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


    Хочу спросить: ведь Ваше высказывание справедливо только для однопроцессорных систем? Рихтер в своей книге писал, что для многопроцессорных систем из-за наличия кеширования данных процессорами могут возникнуть проблемы, особенно при записи. Поэтому он рекомендует запись обязательно синхронизировать, а чтение — на усмотрение. Какое Ваше мнение по этому поводу?
    ... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
    Re[6]: Работа с потоками в C#. Часть 1.
    От: rsn81 Россия http://rsn81.wordpress.com
    Дата: 31.05.07 09:43
    Оценка:
    Здравствуйте, Mika Soukhov, Вы писали:

    MS>Вообще, нужно было сразу делать поля неизменяемыми. И, если они должны изменятся, нужно явно помечать поле как mutable.

    Ага, подход Nemerle в этом отношении более привлекателен.

    Я решаю эту проблему автоматическим рефакторингом: среда разработки пробегает по коду и все переменные, которые может, делает неизменяемыми.
    ... << RSDN@Home 1.2.0 alpha rev. 677>>
    Re[8]: Работа с потоками в C#. Часть 1.
    От: rsn81 Россия http://rsn81.wordpress.com
    Дата: 31.05.07 09:48
    Оценка:
    Здравствуйте, tol05, Вы писали:

    Атомарность операции и означает, что после ее выполнения данные будут доступны всем потокам, т.е. не будут находиться в регистрах, локальном кэше процессора и т.п.
    ... << RSDN@Home 1.2.0 alpha rev. 677>>
    Re[5]: Работа с потоками в C#. Часть 1.
    От: _FRED_ Черногория
    Дата: 31.05.07 09:50
    Оценка:
    Здравствуйте, rsn81, Вы писали:

    R>Если резюмировать: безопасность инициализации по умолчанию является потоковой — и это может жестко обеспечить readonly. Так, например, в Java тоже делает final.


    R>Может быть неправ (по-крайнем мере в Java это так), но мне кажется в примерах в принципе все корректно.


    Некоректно, с моей точки зрения, то, что ничто (кроме здравого смысла) не мешает мне в какой-нить хакерской функции переприсвоить значение "объекта синхронизации":
    class Test
    {
      static object syncLock = new object();
    
      static void Proc1() {
        lock(syncLock) {
          // bla-bla-bla
        }//lock
      }
    
      static void Proc2() {
        lock(syncLock) {
          // bla-bla-bla
        }//lock
      }
    
      static void ProcXXX() {
        lock(syncLock) {
          syncLock = 8; // Без readonly этому нично не мешает. 
                        // Грабли в этом переприсвоении читателю предлагается найти самому ;о)
        }//lock
      }
    }
    Help will always be given at Hogwarts to those who ask for it.
    Re[8]: Работа с потоками в C#. Часть 1.
    От: Mika Soukhov Stock#
    Дата: 31.05.07 09:58
    Оценка:
    Здравствуйте, tol05, Вы писали:

    T>Здравствуйте, Mika Soukhov, Вы писали:


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


    T>Хочу спросить: ведь Ваше высказывание справедливо только для однопроцессорных систем? Рихтер в своей книге писал, что для многопроцессорных систем из-за наличия кеширования данных процессорами могут возникнуть проблемы, особенно при записи.


    Лечиться write barrier и применяется volitile. Наверное и для многоядерных такое справедливо. У них тоже свой несколько кешей.

    T>Поэтому он рекомендует запись обязательно синхронизировать, а чтение — на усмотрение. Какое Ваше мнение по этому поводу?


    Обычные сценарии таковы, что:

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

    Volitile вообще применяется довольно редко. Нужно уж очень специфичную ситуацию, когда без него необойтись.
    Re[6]: Работа с потоками в C#. Часть 1.
    От: rsn81 Россия http://rsn81.wordpress.com
    Дата: 31.05.07 10:01
    Оценка:
    Здравствуйте, _FRED_, Вы писали:

    _FR>Грабли в этом переприсвоении читателю предлагается найти самому ;о)

    Я глупый, объясните мне, что плохого?
    Намекаете, что при выходе из lock блокировка с "потерянного" объекта не снимется? Не верю, а MSVS нет под рукой проверить... Это точно так?
    ... << RSDN@Home 1.2.0 alpha rev. 677>>
    Re[10]: Работа с потоками в C#. Часть 1.
    От: rsn81 Россия http://rsn81.wordpress.com
    Дата: 31.05.07 10:05
    Оценка:
    Здравствуйте, Максим Зелинский, Вы писали:

    Ага, не прав, бес попутал.
    ... << RSDN@Home 1.2.0 alpha rev. 677>>
    Re[11]: Работа с потоками в C#. Часть 1.
    От: Максим Зелинский  
    Дата: 31.05.07 10:09
    Оценка:
    Здравствуйте, Mika Soukhov, Вы писали:

    MS>Здравствуйте, Максим Зелинский, Вы писали:


    МЗ>>Разве? Всегда считал, что атомарность значит "нераздельно". В плане команд это значит, что атомарную инструкцию будет выполнять всегда один поток.


    MS>Вроде как все инструкции атомарны. Или ты про операции?

    Да, операции
    ... << RSDN@Home 1.2.0 alpha rev. 679>>
    Re[9]: Работа с потоками в C#. Часть 1.
    От: tol05  
    Дата: 31.05.07 10:13
    Оценка:
    Здравствуйте, Максим Зелинский, rsn81, вы писали:
    (вы извините, но я не хочу раздувать ветки темы и в одной теме хочу задать вопрос обоим вам ) Но меня эта тема заинтересовала и я буду рад, если вы мне, все же ответите.

    Максим Зелинский, вы писали:
    МЗ>Не смешивайте. Проблемы с кэшем решаются через volitale и ему подобные конструкции, а блокировать ли на чтение, это уже другой вопрос, не имеющий отношение к кэшу.

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

    Я не большой специалист в этой области и могу ошибаться... Мне непонятно, почему Вы, считаете, что блокировка на чтение не имеет значение к кешу? Ведь при работающем кешировании данные будут считываться из памяти только в первый раз, а во второй — браться из кеша?

    rsn81, вы писали:
    R>Атомарность операции и означает, что после ее выполнения данные будут доступны всем потокам, т.е. не будут находиться в регистрах, локальном кэше процессора и т.п.
    Спасибо за ответ. Допустим, я в данный момент пишу вам ответ на двухпроцессорной машине. Чем сейчас (без введения дополнительных программных конструкций) обеспечиваетя атомарность операций над моимим данными?
    ... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
    Re[10]: Работа с потоками в C#. Часть 1.
    От: tol05  
    Дата: 31.05.07 10:14
    Оценка:
    Все, спасибо, читаю ответы Синхронизирую данные

    T>rsn81, вы писали:

    R>>Атомарность операции и означает, что после ее выполнения данные будут доступны всем потокам, т.е. не будут находиться в регистрах, локальном кэше процессора и т.п.
    T>Спасибо за ответ. Допустим, я в данный момент пишу вам ответ на двухпроцессорной машине. Чем сейчас (без введения дополнительных программных конструкций) обеспечиваетя атомарность операций над моимим данными?
    ... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
    Re[5]: Работа с потоками в C#. Часть 1.
    От: .Den Украина  
    Дата: 31.05.07 10:49
    Оценка:
    Здравствуйте, Mika Soukhov:

    Пример с lock:
    1. Вычитывание из i
    2. Инкримент
    3. Запись в i
    4. Присваивание 123 в i
    результат i == 123
    или
    1. Присваивание 123 в i
    2. Вычитывание из i
    3. Инкримент
    4. Запись в i
    результат i == 124

    Без lock:
    1. Вычитывание из i
    2. Присваивание 123 в i
    3. Инкримент
    4. Запись в i
    или
    1. Вычитывание из i
    2. Инкримент
    3. Присваивание 123 в i
    4. Запись в i
    результат i == 123
    или любой из вышеприведенных случаев (результат 123 либо 124).
    Чем здесь lock помогает на присваивании? 100% тратятся зря ресурсы, толку ровно ноль. Пример неудачный.
    Re[5]: Работа с потоками в C#. Часть 1.
    От: .Den Украина  
    Дата: 31.05.07 10:53
    Оценка:
    Здравствуйте, Mika Soukhov, Вы писали:

    MS>

    MS>Как правило, любое поле, доступное нескольким потокам, должно читаться и записываться с блокировкой. Даже в самом простом случае, операции присваивания одиночному полю, необходима синхронизация. В следующем классе ни приращение, ни присваивание не потокобезопасны:


    MS>Выделенное — неправильно. Но на удивление, сам пример корректен.

    Пример на столько же корректен, как был бы и без lock в присваивании.
    Re[6]: Работа с потоками в C#. Часть 1.
    От: Mika Soukhov Stock#
    Дата: 31.05.07 11:51
    Оценка:
    Здравствуйте, .Den, Вы писали:

    D>Здравствуйте, Mika Soukhov:


    D>Пример с lock:

    D>1. Вычитывание из i
    D>2. Инкримент
    D>3. Запись в i
    D>4. Присваивание 123 в i
    D>результат i == 123
    D>или
    D>1. Присваивание 123 в i
    D>2. Вычитывание из i
    D>3. Инкримент
    D>4. Запись в i
    D>результат i == 124

    D>Без lock:

    D>1. Вычитывание из i
    D>2. Присваивание 123 в i
    D>3. Инкримент
    D>4. Запись в i
    D>или
    D>1. Вычитывание из i
    D>2. Инкримент
    D>3. Присваивание 123 в i
    D>4. Запись в i

    1. Присваивание 123 в i
    2. Вычитывание из i
    3. Присваивание 123 в i
    4. Инкримент
    5. Присваивание 123 в i
    6. Запись в i

    D>результат i == 123

    D>или любой из вышеприведенных случаев (результат 123 либо 124).

    Вариантом поведения больше. Чем в программе больше вариантов, тем меньше у программиста желание это мейнтейнить.

    D>Чем здесь lock помогает на присваивании? 100% тратятся зря ресурсы, толку ровно ноль. Пример неудачный.


    Может. Статья то явно уровня 200. Так что может и лучше, что все так просто и примитивно.
    Re[8]: Работа с потоками в C#. Часть 1.
    От: Mika Soukhov Stock#
    Дата: 31.05.07 11:54
    Оценка:
    Здравствуйте, Sinclair, Вы писали:

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


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


    _FR>>>Грабли в этом переприсвоении читателю предлагается найти самому ;о)

    R>>Я глупый, объясните мне, что плохого?
    R>>Намекаете, что при выходе из lock блокировка с "потерянного" объекта не снимется? Не верю, а MSVS нет под рукой проверить... Это точно так?
    S>Это точно не так.
    S>Но зато сразу после переприсвоения, еще до отпускания старого лока, другой поток сможет легко войти в защищенную lock-ом зону, т.к. будет блокироваться на другом объекте.

    Я даже более могу сказать. В лок можно передавать объекты велью типов . Эдакий подход распараллеливания процессов. Надо вводить женерик тип лока.
    Re[7]: Работа с потоками в C#. Часть 1.
    От: .Den Украина  
    Дата: 31.05.07 11:58
    Оценка:
    Здравствуйте, Mika Soukhov, Вы писали:

    MS>1. Присваивание 123 в i

    MS>2. Вычитывание из i
    MS>3. Присваивание 123 в i
    MS>4. Инкримент
    MS>5. Присваивание 123 в i
    MS>6. Запись в i

    Ну так напиши как изменится результат с использованием lock'а??

    1. Присваивание 123 в i
    3. Присваивание 123 в i
    3. Присваивание 123 в i
    2. Вычитывание из i
    4. Инкримент
    6. Запись в i

    Будет ли такое поведение по-другому отражено в значении переменной?
    Re[9]: Работа с потоками в C#. Часть 1.
    От: Кэр  
    Дата: 31.05.07 12:08
    Оценка:
    Здравствуйте, Mika Soukhov, Вы писали:

    MS>Я даже более могу сказать. В лок можно передавать объекты велью типов . Эдакий подход распараллеливания процессов. Надо вводить женерик тип лока.


    Надо ли? Так или иначе lock работает через object. К object можно привести что угодно
    ... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
    Re[7]: Работа с потоками в C#. Часть 1.
    От: Mika Soukhov Stock#
    Дата: 31.05.07 12:09
    Оценка:
    Здравствуйте, rsn81, Вы писали:

    R>

    Безопасность инициализации

    R>Новая модель памяти JMM также старается предоставить новые гарантии безопасности инициализации. То есть, если объект соответствующим образом сконструирован (то есть ссылка на объект не опубликована, пока конструирование не завершено), тогда все потоки будут видеть значения его полей final, которые были установлены конструктором, независимо от того, используется ли синхронизация, чтобы передать ссылку из одного потока другому. Более того, переменные, которые могут быть доступны через поле final должным образом сконструированного объекта, например поля объекта, на который ссылается поле final, также гарантированно видимы другим потокам. Это значит, что если поле final содержит ссылку на, скажем, LinkedList, кроме видимости правильного значения ссылки другим потокам, содержимое этого LinkedList во время конструирования будет доступно другим потокам без синхронизации. Результат этого — значительное усиление значения final, то есть поля final могут быть безопасно доступны без синхронизации, и компиляторы могут предположить, что поля final не изменятся, и следовательно смогут оптимизировать множественные выборки.


    Сразу скажу, что ничего практически не понял, кроме последнего. В .NET насколько я могу предполагать оптимизируются только константы (вшиваются прямо в код, без обращения по адресу). Readonly поля на самом деле можно изменять, но только через reflection.

    Если я ответил на твой вопрос — я рад.
    Re[9]: Работа с потоками в C#. Часть 1.
    От: tol05  
    Дата: 31.05.07 12:11
    Оценка:
    Здравствуйте, Mika Soukhov, Вы писали:

    MS>Я даже более могу сказать. В лок можно передавать объекты велью типов

    А в чем тогда смысл лока? Value типы не имеют индекса синхронизации, как же один поток узнает, что переменная заблокирована другим потоком?
    ... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
    Re[8]: Работа с потоками в C#. Часть 1.
    От: rsn81 Россия http://rsn81.wordpress.com
    Дата: 31.05.07 13:53
    Оценка:
    Здравствуйте, Mika Soukhov, Вы писали:

    MS>Сразу скажу, что ничего практически не понял, кроме последнего.

    Речь про один аспект синхронизации, о котором многие и не думают, видимости. То есть если поток_1 производит вычисление переменной_1 в значение_1, как другой поток_2 увидит значение_1?

    А причины, по которой поток_2 увидит в переменной_1 не значение_1, следующие. Компиляторы, среда выполнения и кэш обычно вправе перераспределять инструкции по своему усмотрению в сторону большей эффективности, если не рушится семантическая последовательность.

    Термин переупорядочивание используется для описания нескольких классов реальных и очевидных перераспределений операций с памятью:


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

    (с) из той же статьи

    К примеру, в старой версии Java 1.3 такой пример мог выполнится не так, как задумывалось:

    volatile boolean initialized = false;
    // запретили initialized хранить в локальной памяти:
    // кэши, регистры, аппаратные средства, оптимизация программы в процессе компилирования и т.п.
    // и наивно надеемся, что все будет OK
    
    // В потоке_1
    HashMap config = new HashMap();
    init(config);
    initialized = true;
    
    // В потоке_2
    while (!initialized) 
        sleep();
    // инициализация закончена, начинаем использовать config
    config.get("someProperty"); // получаем null, что такое?

    Дело в том, что раньше операциям записи не volatile-переменных позволялось быть перераспределенными с операцими записи volatile-переменных. В итоге, весьма возможна ситуация, когда initialized == true, но config еще не заполнен необходимыми данными. В последующих версиях перераспределение операций чтения-записи volatile-переменных с такими же операциями по другим переменным решили запретить — код приведенный выше стал исполняться гарантированно, правда, чуть медленнее.

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

    MS>Если я ответил на твой вопрос — я рад.

    Речь о том, что синхронизация это не только synchronized (lock в .NET), т.е. взаимное исключение, не дающее более чем одному объекту зайти в потокоопасный участок кода, но и правила видимости памяти: сброс кэш при выходе из synchronized-блока, объявление их недействительными при входе в него, запрет компилятору перемещать инструкции изнутри synchronized-блока наружу, правда, внутрь можно.

    PS Еще раз повторюсь, так в Java, в .NET так детально не знаю, но подозреваю, что аналогично... Потому и заинтересовала данная статья и это обсуждение.
    Re[11]: Работа с потоками в C#. Часть 1.
    От: tol05  
    Дата: 31.05.07 13:55
    Оценка:
    Здравствуйте, Mika Soukhov, Вы писали:

    MS>Аргумент каждый раз боксится, и в лок передается новый объект. Вообщем, рассматривай это как bad (maybe worst) practic.


    В том-то и дело, что переменная int myInt, требуемая двум потокам, не будет синхронизирована, ее упакованная копия синхронизируется. Но ведь пока один поток с переменной (вернее, с ее упакованным значением) работает в функции
    f()
    {
    lock(this.myInt)
    {
    }
    }

    второй может это значение изменить несколькими вызовами
    F1()
    {
    this.myInt += 10;
    }

    и что произойдет с this.myInt, когда первый поток закончит работу?
    ... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
    Re[9]: Работа с потоками в C#. Часть 1.
    От: romangr Россия  
    Дата: 31.05.07 14:50
    Оценка:
    Здравствуйте, rsn81, Вы писали:

    R>PS Еще раз повторюсь, так в Java, в .NET так детально не знаю, но подозреваю, что аналогично... Потому и заинтересовала данная статья и это обсуждение.


    Как сделано в .NET немного проясняет статья Memory Consistency &amp; .NET
    ... << RSDN@Home 1.2.0 alpha rev. 670>>
    Re[9]: Работа с потоками в C#. Часть 1.
    От: tol05  
    Дата: 31.05.07 15:56
    Оценка:
    Здравствуйте, FDSC, Вы писали:

    FDS>Кэши синхронизируются аппаратно независимо от локов программиста. Операция инкремента то же может быть вызвана без локов, если она осуществляется командой inc с префиском lock, который блокирует системную шину

    о команде inc с префиском lock я не слышал, если честно... Это не lock. А что? Как мне осуществить инкремент такой командой?
    И еще, по Вашему получается, что volatile — лишний оператор, а Рихтер зря PowerThreading Library написал и статьи каждые несколько месяцев зря писать продолжает?

    Я говорил, что в этой области не специалист, Ваши слова меня смущают.
    ... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
    Re[8]: Работа с потоками в C#. Часть 1.
    От: rsn81 Россия http://rsn81.wordpress.com
    Дата: 31.05.07 15:57
    Оценка:
    Здравствуйте, 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();
            }
        }
    }
    В консоли видим:
    Enter
    Enter
    Exit
    Exit

    Да-а-а, mutable по умолчанию все-таки зло.
    Re[10]: Работа с потоками в C#. Часть 1.
    От: FDSC Россия consp11.github.io блог
    Дата: 31.05.07 18:56
    Оценка:
    Здравствуйте, tol05, Вы писали:

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


    FDS>>Кэши синхронизируются аппаратно независимо от локов программиста. Операция инкремента то же может быть вызвана без локов, если она осуществляется командой inc с префиском lock, который блокирует системную шину

    T>о команде inc с префиском lock я не слышал, если честно... Это не lock. А что? Как мне осуществить инкремент такой командой?
    T>И еще, по Вашему получается, что volatile — лишний оператор, а Рихтер зря PowerThreading Library написал и статьи каждые несколько месяцев зря писать продолжает?

    T>Я говорил, что в этой области не специалист, Ваши слова меня смущают.


    Ну как сказать. Я не видел, что конкретно пишет Рихтер. lock inc — это команда процессора, если вы программируете на ассемблере, можете её применить. А как это на верхнем уровне синхронизируется, это уже другой вопрос.

    Но с кэшами процессора Рихтер чего-то недопонял, если он действительно говорил, что нужна синхронизация ради кэшей...
    Re[9]: Работа с потоками в C#. Часть 1.
    От: rsn81 Россия http://rsn81.wordpress.com
    Дата: 01.06.07 02:20
    Оценка:
    Здравствуйте, FDSC, Вы писали:

    FDS>Кэши синхронизируются аппаратно независимо от локов программиста.

    Гм...
    ... << RSDN@Home 1.2.0 alpha rev. 677>>
    Re[9]: Работа с потоками в C#. Часть 1.
    От: Максим Зелинский  
    Дата: 01.06.07 08:03
    Оценка:
    Здравствуйте, FDSC, Вы писали:

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


    T>>Здравствуйте, Mika Soukhov, Вы писали:


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


    T>>Хочу спросить: ведь Ваше высказывание справедливо только для однопроцессорных систем? Рихтер в своей книге писал, что для многопроцессорных систем из-за наличия кеширования данных процессорами могут возникнуть проблемы, особенно при записи. Поэтому он рекомендует запись обязательно синхронизировать, а чтение — на усмотрение. Какое Ваше мнение по этому поводу?


    FDS>Кэши синхронизируются аппаратно независимо от локов программиста. Операция инкремента то же может быть вызвана без локов, если она осуществляется командой inc с префиском lock, который блокирует системную шину

    Всмысле? Не надо использовать volitale? Мучаться с memory barrier и т.д.?
    недопонял
    ... << RSDN@Home 1.2.0 alpha rev. 679>>
    Re[7]: Работа с потоками в C#. Часть 1.
    От: ie Россия http://ziez.blogspot.com/
    Дата: 01.06.07 10:17
    Оценка:
    Здравствуйте, rsn81, Вы писали:

    R> Я решаю эту проблему автоматическим рефакторингом: среда разработки пробегает по коду и все переменные, которые может, делает неизменяемыми.


    А кто это так умеет?
    ... << RSDN@Home 1.2.0 alpha rev. 0>>
    Превратим окружающую нас среду в воскресенье.
    Re[9]: Работа с потоками в C#. Часть 1.
    От: rsn81 Россия http://rsn81.wordpress.com
    Дата: 01.06.07 10:19
    Оценка:
    Здравствуйте, 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.

    cbrumme's WebLog, Memory Model

    По сути пример показывает ту же ошибку видимости, что и приводил выше в отношении Java. То есть lock в том числе и дает команду на сброс кешей. Или я вас неправильно понял?
    ... << RSDN@Home 1.2.0 alpha rev. 677>>
    Re[8]: Работа с потоками в C#. Часть 1.
    От: rsn81 Россия http://rsn81.wordpress.com
    Дата: 01.06.07 10:22
    Оценка:
    Здравствуйте, ie, Вы писали:

    ie>А кто это так умеет?

    Eclipse SDK 3.3 (source code cleanup refactoring).
    ... << RSDN@Home 1.2.0 alpha rev. 677>>
    Re[10]: Работа с потоками в C#. Часть 1.
    От: FDSC Россия consp11.github.io блог
    Дата: 01.06.07 10:35
    Оценка:
    Здравствуйте, Максим Зелинский, Вы писали:

    FDS>>Кэши синхронизируются аппаратно независимо от локов программиста. Операция инкремента то же может быть вызвана без локов, если она осуществляется командой inc с префиском lock, который блокирует системную шину

    МЗ>Всмысле? Не надо использовать volitale? Мучаться с memory barrier и т.д.?
    МЗ>недопонял


    Ммм, я вас то же не допонял. Мы, кажется, о разном говорим. Я всего лишь говорю, что синхронизация не требуется для записи и должна осуществляться аппаратно
    Re[10]: Работа с потоками в C#. Часть 1.
    От: FDSC Россия consp11.github.io блог
    Дата: 01.06.07 10:45
    Оценка:
    Здравствуйте, rsn81, Вы писали:

    R>

    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, если это операция записи элементарного типа
    Re[11]: Работа с потоками в C#. Часть 1.
    От: Максим Зелинский  
    Дата: 01.06.07 10:52
    Оценка:
    Здравствуйте, FDSC, Вы писали:

    FDS>Ммм, я вас то же не допонял. Мы, кажется, о разном говорим. Я всего лишь говорю, что синхронизация не требуется для записи и должна осуществляться аппаратно

    действительно. вот теперь понятно
    ... << RSDN@Home 1.2.0 alpha rev. 679>>
     
    Подождите ...
    Wait...
    Пока на собственное сообщение не было ответов, его можно удалить.