VarHandle get / setOpaque - PullRequest
       40

VarHandle get / setOpaque

3 голосов
/ 28 мая 2019

Я продолжаю бороться, чтобы понять, что VarHandle::setOpaque и VarHandle::getOpaque действительно делают .До сих пор это было нелегко - есть некоторые вещи, которые я думаю я получаю (но не буду представлять их в самом вопросе, а не в мутной воде), но в целом это в лучшем случае неэффективно дляme.

Документация:

Возвращает значение переменной, доступ к которой осуществляется в программном порядке ...

В моем понимании, если у меня есть:

int xx = x; // read x
int yy = y; // read y

Эти чтения можно переупорядочить.С другой стороны, если у меня есть:

// simplified code, does not compile, but reads happen on the same "this" for example
int xx = VarHandle_X.getOpaque(x); 
int yy = VarHandle_Y.getOpaque(y);

На этот раз повторные заказы невозможны?И это что значит "программный заказ"?Мы говорим о вставке барьеров здесь для того, чтобы этот повторный заказ был запрещен?Если это так, поскольку это две нагрузки, будет ли достигнуто то же самое?через:

 int xx = x;
 VarHandle.loadLoadFence()
 int yy = y;

Но все становится намного сложнее:

... но без уверенности в эффектах упорядочения памяти по отношению к другим потокам.

Я не мог придумать пример, чтобы притвориться, что я понимаю эту часть.

Мне кажется, что эта документация предназначена для людей, которые точно знают, что они делают (а я определенно не один) ... Так может кто-нибудь пролить свет здесь?

Ответы [ 2 ]

4 голосов
/ 28 мая 2019

В моем понимании, если у меня есть:

int xx = x; // read x
int yy = y; // read y

Эти чтения могут быть переупорядочены.

Эти чтения могут быть не только переупорядочены,они могут не произойти вообще.Поток может использовать старое, ранее прочитанное значение для x и / или y или значений, которые он ранее записывал в эти переменные, тогда как на самом деле запись, возможно, еще не была выполнена, поэтому «поток чтения» можетиспользуйте значения, о которых другие потоки не могут знать и не находятся в куче памяти в это время (и, вероятно, никогда не будут).

С другой стороны, если у меня есть:

// simplified code, does not compile, but reads happen on the same "this" for example
int xx = VarHandle_X.getOpaque(x); 
int yy = VarHandle_Y.getOpaque(y);

На этот раз повторные заказы невозможны?И это то, что означает «программный порядок»?

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

Определен термин программный порядок JLS:

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

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

Мы говорим здесь о вставке барьеров для запрета этого переупорядочения?

Нет, в этом нет никакого препятствия, которое может заключаться в фразе «… но без уверенности в эффектах упорядочения памяти по отношению к другим потокам ».

ВозможноМожно сказать, что непрозрачный доступ работает примерно так же, как volatile до Java 5, обеспечивая доступ для чтения, чтобы увидеть самое последнее значение памяти кучи (что имеет смысл, только если конец записи также использует непрозрачный или даже более сильный режим), нобез влияния на другие операции чтения или записи.

Так что вы можете с этим сделать?

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

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

Это также полезно, если вы просто хотите атомарный доступ для long и double, без каких-либо других последствий.

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

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

0 голосов
/ 05 июня 2019

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

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

запись заказана с пересылкой из буфера хранилища

модель памяти, так что даже если поток сохраняет до загрузки. Хранилище может быть кэшировано в буфере хранилища, и некоторый поток, выполняемый на любом другом ядре, наблюдает за действием потока в обратном порядке load-store вместо store-load. Так что непрозрачная операция выполняется на x86 бесплатно (на x86 мы также получили бесплатно, посмотрите этот исчерпывающий ответ для деталей о некоторых других архитектурах и их моделях памяти: https://stackoverflow.com/a/55741922/8990329)

Почему это полезно? Что ж, я могу предположить, что если какой-то поток обнаружит значение, хранящееся в непрозрачной семантической памяти, то при последующем чтении будет получено значение «хотя бы это или позже» (простой доступ к памяти не дает таких гарантий, не так ли?).

Кроме того, поскольку Java 9 VarHandles в некоторой степени связаны с семантикой получения / выпуска / потребления в C, я думаю, что стоит отметить, что непрозрачный доступ похож на memory_order_relaxed, который определен в Стандарте следующим образом:

Для memory_order_relaxed, нет памяти операций заказов.

с некоторыми примерами.

...