Взаимно блокируемые и барьеры памяти

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

пользователь будет вводить Вашу систему и использовать ее для достижения цели. При открытии calc, необходимо сделать простое быстрое вычисление 90% времени так вот почему по умолчанию, это установлено на простой режим.

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

12
задан 18 November 2009 в 18:07
поделиться

7 ответов

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

while (!pShared->lock.testAndSet_Acquire()) ;
// (this loop should include all the normal critical section stuff like
// spin, waste, 
// pause() instructions, and last-resort-give-up-and-blocking on a resource 
// until the lock is made available.)

// Access to shared memory.

pShared->foo = 1 
v = pShared-> goo

pShared->lock.clear_Release()

Получение барьера памяти выше гарантирует, что любые загрузки (pShared-> goo), которые могли быть запущены до успешной модификации блокировки, будут отброшены, чтобы быть перезапущенными в случае необходимости .

Барьер освобождения памяти гарантирует, что загрузка из goo в (скажем, локальную) переменную v будет завершена до того, как будет очищено слово блокировки, защищающее разделяемую память.

У вас есть похожий шаблон в типичных атомарных источниках и потребителях flag scenerio (по вашему образцу трудно сказать, что вы делаете, но он должен иллюстрировать идею).

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

pShared->goo = 14

pShared->atomic.setBit_Release()

Без барьера "записи" здесь, в производителе, у вас нет гарантии, что оборудование не попадет в атомарное хранилище до того, как хранилище goo пройдет через очереди хранилища ЦП. , и вверх по иерархии памяти, где это видно (даже если у вас есть механизм, который гарантирует, что компилятор упорядочивает вещи так, как вы хотите).

В потребителе

if ( pShared->atomic.compareAndSwap_Acquire(1,1) )
{
   v = pShared->goo 
}

Без барьера для чтения здесь вы не сможете знайте, что оборудование не ушло и не принесло вам слизь до завершения атомарного доступа. Атомарная (то есть: память, управляемая блокированными функциями, выполняющими такие вещи, как lock cmpxchg), является «атомарной» только по отношению к себе, а не к другой памяти.

Теперь, Остается упомянуть, что барьерные конструкции крайне непереносимы. Ваш компилятор, вероятно, предоставляет варианты _acquire и _release для большинства методов атомарной манипуляции, и вы бы могли их использовать именно так. В зависимости от платформы, которую вы используете (например, ia32), они вполне могут быть именно тем, что вы получили бы без суффиксов _acquire () или _release (). Платформы, где это имеет значение, - это ia64 (фактически мертвый, за исключением HP, где он все еще немного дергается) и powerpc. ia64 имеет модификаторы инструкций .acq и .rel для большинства инструкций загрузки и сохранения (включая атомарные, такие как cmpxchg). В powerpc есть отдельные инструкции для этого (isync и lwsync обеспечивают защиту от чтения и записи соответственно).

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

4
ответ дан 2 December 2019 в 21:23
поделиться

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

Что вам действительно нужно, так это атомарные операции, т.е. Функции InterlockedXXX или изменчивые переменные в C #. Если бы чтение в Bar было атомарным, вы могли бы гарантировать, что ни компилятор, ни процессор не выполнят никаких оптимизаций, которые не позволят ему прочитать значение перед записью в Foo или после записи в Foo, в зависимости от того, что выполняется первым.

5
ответ дан 2 December 2019 в 21:23
поделиться

Я не совсем уверен, но думаю, что Interlocked.Exchange будет использовать функцию InterlockedExchange API Windows , которая в любом случае обеспечивает полный барьер памяти.

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

2
ответ дан 2 December 2019 в 21:23
поделиться

Операции взаимоблокированного обмена гарантируют барьер памяти.

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

  • Функции, которые входят в критические разделы или выходят из них

  • Функции, которые сигнализируют об объектах синхронизации

  • Функции ожидания

  • Связанные функции

(Источник: ссылка )

Но вам не повезло с регистровыми переменными. Если m_value находится в регистре в Bar, вы не увидите изменения m_value. В связи с этим вам следует объявить общие переменные "volatile".

1
ответ дан 2 December 2019 в 21:23
поделиться

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

1
ответ дан 2 December 2019 в 21:23
поделиться

Interlocked.Exchange () должен гарантировать, что значение сбрасывается на все процессоры должным образом - он обеспечивает свой собственный барьер памяти.

Я удивлен, что компилятор скомпилировал передачу изменчивого в Interlocked.Exchange () - тот факт, что вы используете Interlocked.Exchange (), должен почти указывать на изменчивую переменную.

Проблема, которую вы могли бы увидеть, заключается в том, что если компилятор произведет серьезную оптимизацию Bar () и понимает, что ничего не меняет значение m_value, он может оптимизировать вашу проверку. Вот что будет делать ключевое слово volatile - оно намекнет компилятору, что эта переменная может быть изменена вне поля зрения оптимизатора.

0
ответ дан 2 December 2019 в 21:23
поделиться

If you don't tell the compiler or runtime that m_value should not be read ahead of Bar(), it can and may cache the value of m_value ahead of Bar() and simply use the cached value. If you want to ensure that it sees the "latest" version of m_value, either shove in a Thread.MemoryBarrier() or use Thread.VolatileRead(ref m_value). The latter is less expensive than a full memory barrier.

Ideally you could shove in a ReadBarrier, but the CLR doesn't seem to support that directly.

EDIT: Another way to think about it is that there are really two kinds of memory barriers: compiler memory barriers that tell the compiler how to sequence reads and writes and CPU memory barriers that tell the CPU how to sequence reads and writes. The Interlocked functions use CPU memory barriers. Even if the compiler treated them as compiler memory barriers, it still wouldn't matter, as in this specific case, Bar() could have been separately compiled and not known of the other uses of m_value that would require a compiler memory barrier.

0
ответ дан 2 December 2019 в 21:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: