EventWaitHandle имеет какой-либо неявный MemoryBarrier?

Тернарный оператор

Для краткого синтаксиса используйте троичный оператор:

var / const / let переменная [ 1115] = ( условие ) ? значение, если true : значение, если false

blockquote>

Скобка, заключенная в скобки условия являются необязательными.


Демонстрация

/* 
Condition: if (number is greater than 10) ?
             return true 
           : else return false
*/
const gTTen = number => { return (number > 10) ? true : false; }

console.log(gTTen(11));
console.log(gTTen(9));

function ternary(number) {

  /*
  Using the previous function then store its return in a 
  variable
  */
  const tenFilter = gTTen(number);
  
  /*
  Condition: if (previous value is true AND the number is
             less than 20) ?
               range is 30
               : else range is 0
  */
  let range = (tenFilter && number < 20) ? 30 : 0; 
  
  /*
  Condition: if (range = 30) ? 
               result is (the first string)
               : else result is (the last string)
  */               
  let result = range === 30 ? `${number} is within range` : `${number} is not within range`;
  
  return result;
}

console.log(ternary(50));
console.log(ternary(15));

10
задан tcarvin 30 March 2009 в 12:24
поделиться

4 ответа

Обратите внимание, что это неподготовлено, не изучая Ваш код тесно. Я не думаю, что Набор выполняет барьер памяти, но я не вижу, как это релевантно в Вашем коде? Походит более важный, был бы то, если Ожидают, работает один, который это делает. Таким образом, если я не пропустил что-то за эти 10 секунд, я посвятил рассмотрению Вашего кода, я не полагаю, что Вам нужны летучие вещества.

Править: Комментарии слишком строги. Я теперь обращаюсь к редактированию Matt.

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

Энергозависимое чтение читает значение и затем делает недействительным кэш ЦП. Энергозависимая запись сбрасывает кэш и затем пишет значение. Барьер памяти сбрасывает кэш и затем делает недействительным его.

Модель памяти.NET гарантирует, что все записи энергозависимы. Чтения, по умолчанию, не, если явный VolatileRead не сделан, или энергозависимое ключевое слово указано на поле. Далее, взаимно блокируемые методы вызывают когерентность кэш-памяти и все понятия синхронизации (Монитор, ReaderWriterLock, Взаимное исключение, Семафор, AutoResetEvent, ManualResetEvent, и т.д.), вызов взаимно блокировал методы внутренне, и таким образом гарантируйте когерентность кэш-памяти.

Снова, все это из книги Jeffrey Richter, "CLR через C#".

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

Я поддерживаю свое исходное утверждение, которое энергозависимый не нужно здесь.

Редактирование 2: выглядит, как будто Вы создаете "будущее". Я предложил бы, чтобы Вы изучили PFX, вместо того, чтобы прокрутить Ваше собственное.

3
ответ дан 4 December 2019 в 01:32
поделиться

Энергозависимое ключевое слово не должно перепутанный относительно создания _a, _b, и _c ориентированный на многопотоковое исполнение. Посмотрите здесь для лучшего объяснения. Далее, ManualResetEvent не имеет никакого влияния на потокобезопасность _a, _b, и _c. Необходимо управлять этим отдельно.

Править: С этим редактированием я пытаюсь дистиллировать всю информацию, которая была помещена в различные ответы и комментарии относительно этого вопроса.

Основной вопрос состоит в том, будут ли переменные результата (_a, _b, и _c) 'видимы' в то время, когда переменная флага (_completed) возвращает true.

На мгновение давайте предположим, что ни одна из переменных не отмечена энергозависимая. В этом случае для переменных результата было бы возможно быть установленным после того, как переменная флага установлена в Задаче (), как это:

   private void Task()
   {
      // possibly long-running work goes here
      _completed = true;
      _a = result1;
      _b = result2;
      _c = result3;
      _completedSignal.Set();
   }

Это ясно не, что мы хотим, поэтому как заключают нас сделка с этим?

Если эти переменные будут отмечены энергозависимые, то это переупорядочение будет предотвращено. Но именно это запросил исходный вопрос - летучие вещества требуются, или ManualResetEvent обеспечивает неявный барьер памяти, таким образом, что переупорядочение не происходит, в этом случае энергозависимое ключевое слово не действительно необходимо?

Если я понимаю правильно, положение wekempf - то, что WaitOne () функция обеспечивает неявный барьер памяти, который решает проблему. НО это не кажется достаточным мне. Основные и фоновые потоки могли выполняться на двух отдельных процессорах. Так, если Установлено () также не обеспечивает неявный барьер памяти, затем Задача (), функция могла закончить тем, что была выполнена как это на одном из процессоров (даже с энергозависимыми переменными):

   private void Task()
   {
      // possibly long-running work goes here
      _completedSignal.Set();
      _a = result1;
      _b = result2;
      _c = result3;
      _completed = true;
   }

Я искал высоко и низко для получения информации относительно барьеров памяти и EventWaitHandles, и я ничего не придумал. Единственная ссылка, которую я видел, является одним wekempf, сделал к книге Jeffrey Richter. Проблема, которую я имею с этим, состоит в том, что EventWaitHandle предназначен для синхронизации потоков, не доступа к данным. Я никогда не видел примера, где EventWaitHandle (например, ManualResetEvent) используется для синхронизации доступа к данным. По сути, мне трудно полагать, что EventWaitHandle делает что-либо относительно барьеров памяти. Иначе я ожидал бы находить некоторую ссылку на это в Интернете.

РЕДАКТИРОВАНИЕ № 2: Это - ответ на ответ wekempf на мой ответ... ;)

Мне удалось считать раздел из книги Jeffrey Richter по amazon.com. От страницы 628 (wekempf заключает это в кавычки также):

Наконец, я должен указать, что каждый раз, когда поток называет взаимно блокируемый метод, ЦП вызывает когерентность кэш-памяти. Таким образом, при управлении переменными с помощью взаимно блокируемых методов Вы не должны волноваться обо всем этом материале модели памяти. Кроме того, все блокировки синхронизации потока (Монитор, ReaderWriterLock, Взаимное исключение, Semaphone, AutoResetEvent, ManualResetEvent, и т.д.) вызов взаимно блокировали методы внутренне.

Таким образом, казалось бы, что, поскольку wekempf указал, что переменные результата не требуют энергозависимого ключевого слова в примере как показано, так как ManualResetEvent гарантирует когерентность кэш-памяти.

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

Во-первых, мое начальное предположение было то, что фоновый поток будет потенциально работать многократно. Я, очевидно, пропустил название класса (OneUseBackgroundOp)! Учитывая, что это только выполняется однажды, мне не ясно, почему DoSomething () вызовы функции WaitOne () таким образом, что это делает. Какой смысл того, чтобы ожидать initialWaitMs миллисекунды, если фоновый поток может или не может быть сделан в то время DoSomething () возвраты? Почему не только начало фоновый поток и использование блокировка, чтобы синхронизировать доступ к переменным результатов ИЛИ просто выполнить содержание Задачи () функционирует как часть потока, который называет DoSomething ()? Существует ли причина не сделать это?

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

Благодаря всем для терпения меня на этом. Я, конечно, изучил много путем участия в этом обсуждении.

3
ответ дан 4 December 2019 в 01:32
поделиться

На основе того, что Вы показали, я сказал бы что, нет, volatiles не требуются в том коде.

ManualResetEvent самостоятельно не имеет неявного барьера памяти. Однако то, что основной поток ожидает средств связи, что он не может изменить переменные. По крайней мере, это не может изменить переменные, в то время как это ожидает. Таким образом, я предполагаю, что Вы могли сказать, что ожидание на объекте синхронизации является неявным барьером памяти.

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

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

0
ответ дан 4 December 2019 в 01:32
поделиться

Во-первых, я не уверен, должен ли я "Ответить на свой собственный вопрос" или использовать комментарий для этого, но здесь иду:

Мое понимание - то, что энергозависимый препятствует тому, чтобы код/оптимизация памяти переместил доступы к моим переменным результата (и завершенная булевская переменная) таким образом, что поток, который читает результат, будет видеть upt-до-настоящего-времени данные.

Вы не хотели бы _completed булевскую переменную, сделанную видимой ко всем потокам после Набора () из-за компилятора или emmpry optimaztions/reordering. Аналогично, Вы не хотели бы записи к результатам _a, _b, _c замечаемый после Набора ().

Править: Далее explaination/clarification по вопросу, в отношении объектов, упомянутых Matt Davis:

Наконец, я должен указать, что каждый раз, когда поток называет взаимно блокируемый метод, ЦП вызывает когерентность кэш-памяти. Таким образом, при управлении переменными с помощью взаимно блокируемых методов Вы не должны волноваться обо всем этом материале модели памяти. Кроме того, все блокировки синхронизации потока (Монитор, ReaderWriterLock, Взаимное исключение, Semaphone, AutoResetEvent, ManualResetEvent, и т.д.) вызов взаимно блокировали методы внутренне.

Таким образом, казалось бы, что, поскольку wekempf указал, что переменные результата не требуют энергозависимого ключевого слова в примере как показано, так как ManualResetEvent гарантирует когерентность кэш-памяти.

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

Но это предотвращает reording для гарантии таким образом, что И результаты присвоены перед завершенным флагом, и что завершенный флаг присвоен верный, прежде чем ManualResetEvent будет Установлен?

Во-первых, мое начальное предположение было то, что фоновый поток будет потенциально работать многократно. Я, очевидно, пропустил название класса (OneUseBackgroundOp)! Учитывая, что это только выполняется однажды, мне не ясно, почему DoSomething () вызовы функции WaitOne () таким образом, что это делает. Какой смысл того, чтобы ожидать initialWaitMs миллисекунды, если фоновый поток может или не может быть сделан в то время DoSomething () возвраты? Почему не только начало фоновый поток и использование блокировка, чтобы синхронизировать доступ к переменным результатов ИЛИ просто выполнить содержание Задачи () функционирует как часть потока, который называет DoSomething ()? Существует ли причина не сделать это?

Понятие образца состоит в том, чтобы выполнить возможно долгую-runnig задачу. Если задача может быть выполнена в exceptable количестве времени, то вызывающий поток получит доступ к результату и продолжит нормальную обработку. Но когда-то задача может занять довольно долгое время, и поток claiing не может быть заблокирован в течение того периода и может сделать разумные шаги для контакта с этим. Это может включать поиск среди старых изданий позже операции с помощью свойства Completed.

Конкретный пример: твердость DNS часто очень быстрая (подсекунда) и стоящая ожидания даже от GUI, но иногда многим могут потребоваться много секунд. Таким образом при помощи служебного класса как образец, каждый мог получать результат легко с точки зрения вызывающей стороны 95% времени и не запирать GUI другие 5%. Можно было использовать рабочего Background, но это может быть излишеством для операции, что подавляющему большинству времени не нужна вся та инфраструктура.

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

Результат (и завершенный флаг) данные предназначены, чтобы быть неперезаписываемыми, читать много. Если бы я добавил блокировку для присвоения результатов и флага, то я должен был бы также привязать свои методы считывания результата, и мне никогда не нравилось видеть блокировку методов считывания только для возврата точки данных. От моего чтения такая мелкомодульная блокировка не является соответствующей. Если операция имеет 5 или 6 результатов, вызывающая сторона должна взять и выпустить блокировку 5 или 6 раз напрасно.

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

Поскольку у меня есть энергозависимый завершенный флаг, который, как гарантируют, будет установлен, прежде чем энергозависимые результаты будут, и единственный доступ к результатам через методы считывания, и, как упомянуто в smaple, исключение выдается, если бы метод считывания называют, и операция еще не завершена, я ожидал бы что Завершенный и методы считывания результата CAN, который будет вызван потоком кроме того который названный DoSomething (). Это - моя надежда так или иначе. Я полагаю, что это верно с летучими веществами так или иначе.

1
ответ дан 4 December 2019 в 01:32
поделиться