2013-03-12 3 views
10

В Java, когда мы имеем два потока обмена следующие переменные:Что действительно делает барьер LoadLoad?

int a; 
volatile int b; 

если поток 1 делает:

a = 5; 
b = 6; 

Затем StoreStore барьер вставляется между этими двумя инструкциями и «а» быть сбрасывается обратно в основную память.

Теперь, если поток 2 делает:

if(b == 6) 
a++; 

LoadLoad барьер вставляется между ними и есть гарантия, что если новое значение «Ъ» видна, то новое значение «а» видна, а , Но как на самом деле это достигается? Загружает ли LoadLoad кэширование/регистры процессора? Или просто инструктирует CPU для получения значений переменных, которые следуют за чтением из volatile снова из CPU?

Я нашел эту информацию о LoadLoad барьере (http://gee.cs.oswego.edu/dl/jmm/cookbook.html):

LoadLoad барьеры Последовательность: LOAd1; LoadLoad; Load2 гарантирует, что Данные Load1 загружаются до того, как данные будут загружены с помощью Load2, и загрузятся последующие инструкции по загрузке . В общем случае явные барьеры LoadLoad необходимы для процессоров, которые выполняют спекулятивные нагрузки и/или обработку вне очереди, в которых команды ожидания нагрузки могут хранилища ожидания обхода. На процессорах, которые гарантируют сохранение порядка загрузки , барьеры равны нулю.

, но на самом деле это не объясняет, как это достигается.

+0

Ответ зависит от архитектуры процессора - в том же документе есть таблица с каждой инструкцией процессора, которая показывает, что 'LoadLoad' - нет-op на x86, например. – assylias

+0

тогда как это работает вообще? Я имею в виду, что после StoreStore значения будут сброшены обратно в память. Но тогда как поток 2 должен их видеть? Если этот LoadLoad имеет значение no-op, то поток 2 может продолжать использовать кешированные значения. – Janek

+0

, потому что модель памяти процессора достаточно сильна, что гарантирует, что это будет так. Я пытаюсь сказать, что Java дает обещание, что если вы будете использовать volatile, что-то произойдет или не произойдет. Как это реализовано в JVM, зависит от процессора и использует специальные инструкции (или нет инструкции, если это необходимо). Подробнее о точке LoadLoad/x86 можно прочитать здесь: http://altair.cs.oswego.edu/pipermail/concurrency-interest/2012-July/009615.html – assylias

ответ

3

Я приведу один пример о том, как это достигается. Подробную информацию можно найти на странице here. Для x86-процессоров, как вы указали, LoadLoad заканчивается без операций. В статье я связан Марк указывает на то, что

Doug перечисляет StoreStore, LoadLoad и LoadStore

Таким образом, в сущности, единственный барьер нужен является StoreLoad для x86 архитектур. Итак, как это достигается на низком уровне?

Это отрывок из блога:

Вот код, он создается для энергозависимые и энергонезависимые гласит:

nop      ;*synchronization entry 
mov 0x10(%rsi),%rax ;*getfield x 

И для летучих Пишет:

xchg %ax,%ax 
movq $0xab,0x10(%rbx) 
lock addl $0x0,(%rsp)  ;*putfield x 

Инструкция lock является StoreLoad как указано Doug's c ookbook.Но команда блокировки также синхронизирует все читает с другими процессами listed

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

Это уменьшает накладные расходы при выдаче барьеров LoadLoad LoadStore для летучих нагрузок.

Все, что было сказано, я повторю то, что заметили ассирийцы. То, как это происходит, не должно быть важно для разработчика (если вы заинтересованы в реализации процессора/компилятора, это еще одна история). volatile ключевого слова вид интерфейса, говоря

  1. Вы получите наиболее актуальную для чтения, который написан другим потоком
  2. Вы не получите сожжен JIT компилятор оптимизаций.
+0

Хорошая ссылка. Я бы сильно перефразировал: «* Вы получите самое свежее чтение, которое написано другим потоком *» => «* В конце концов вы увидите записи, когда впоследствии читаете из изменчивой переменной -« в конечном счете », что означает почти сразу на практике * ";-) – assylias

+0

На самом деле важно, если вас интересует, какое оборудование работает на вашем компьютере быстрее всего, или о том, как добиться максимальной производительности. Мы надеялись извлечь выгоду из перехода на четырехсетевой Xeon (64 SMT) намного больше, чем мы в итоге сделали. Если вы не имеете никакого контроля над оборудованием или выполняете только на одном сокете, это может быть не проблема, но детали реализации параллелизма и то, как они влияют на масштабируемость на больших машинах, могут, безусловно, влиять на дизайн, если они известны на ранней стадии. –

+0

@ RalfH Я говорил от имени среднего разработчика, используя ключевое слово 'volatile'. Вообще говоря, разработчику не нужно беспокоиться о том, как волатильность реализована.Вы видели экземпляр, когда знаете, что базовая архитектура меняет то, как вы будете использовать изменчивость по-разному? –

0

Если этот LoadLoad имеет значение no-op, то поток 2 может продолжать использовать кешированные значения.

Это покрывается таблицей «Может заказать» в поваренной книге.

Порядок программирования

read b 
read a 
write a 

путь "кэширование", вы имеете в виду кода переупорядочиваются

read a 
... 
read b 

Это переназначение запрещено.

+0

Я на самом деле имел в виду реальное кэширование в кэше CPU, а не переупорядочение команд. – Janek

+0

Нагрузка - это нагрузка, она не будет считываться из регистров CPU. – ZhongYu

+0

@zhong Я думаю, что проблема Janek заключалась в том, «как поле может быть обновлено в регистре процессора, если оно никогда не начнет загрузку после записи другим процессором». –

Смежные вопросы