7 ноября 2012 г.

Если вы знаете, что такое happens-before...

...то ответьте мне на несколько простых вопросов. Дан такой код:


Thread 1

Thread 2

volatile int va;

va = 10;

int b = va;


Вопросы (отвечать желательно по порядку, не забегая вперед):
  1. Какие здесь есть межпоточные ребра HB?
  2. Может ли в b оказаться что-то, кроме 10?
  3. Может ли в b оказаться 0?
  4. Изменится ли что-либо, если здесь заменить volatile store на lazySet?

11 комментариев:

  1. Хм. На мой взгляд, должно быть так:
    1. Здесь есть два ребра hb, порожденные отношением synchronized-with по инициализации переменной 'va', которое должно произойти до первой операции в Thread-1 и Thread-2, соответственно. Кроме того, есть ещё одно ребро hb, которое связывает чтение из va и запись в b (согласно program order). Ну, и транзитивное ребро hb, между начальной инициализацией va и записью в b.
    2. Может.
    3. Может.
    4. В контексте данного примера - ничего.

    ОтветитьУдалить
  2. Этот комментарий был удален автором.

    ОтветитьУдалить
  3. 1. write(va = 0) hb write(va = 10); write(va = 0) hb read(va = 0); write(va = 10) hb read(va = 10);
    2. Может, что угодно, при условии, что в это поле кто-то где-то писал. Если нет, то тоже может, но только 0 и 10.
    3. Может.
    4. Ничего. Равно как и отсутствие volatile вообще.

    ОтветитьУдалить
  4. @aleksey
    -- А... А, это вы, Штирлиц... Идите, и не мешайте работать!

    Нужно было дописать в конце для тебя. А то пришел, и сразу всю интригу поломал :)

    ОтветитьУдалить
  5. @aleksey
    Но-таки отсутствие volatile вообще что-то поменяет - межпоточных ребер hb уже не будет. А?

    @Lerm
    Я из вашего ответа не очень понял -- _меж_поточные ребра-то есть?

    ОтветитьУдалить
  6. Вы не написали в каком порядке физически происходят
    'va = 10' и 'vb = va'. Так вполне возможен такой порядок:
    1. vb = va
    2. va = 10
    тогда в vb будет 0.
    Но если они произошли в таком порядке:
    1. va = 10
    2. vb = va
    То при наличии volatile в vb может быть только 10, а если lazySet, то в vb могут быт и 10, и 0.

    Как-то так.

    ОтветитьУдалить
  7. @artem
    В примере нет vb -- есть просто b, и это просто локальная переменная, она не волатильна.

    ОтветитьУдалить
  8. @ Ruslan

    > Я из вашего ответа не очень понял -- _меж_поточные ребра-то есть?

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

    ОтветитьУдалить
  9. столько комментов и все разные ответы...
    так какой ответ правильный?

    ОтветитьУдалить
    Ответы
    1. Хорошее приближение к условно правильному ответу дал Алексей. Главный поинт в том, что порядки HB/SW/SO являются атрибутом конкретного сценария исполнения, а не кода вообще.

      Удалить
  10. Тут выше написали, что volatile можно убрать, и ничего от этого не изменится, разве это так ? volatile обеспечивает атомарность операций и является synchronization action, поэтому порядок выполнения будет либо (1) и потом (2), либо наоборот, причем в случае, когда первым выполнится write, read будет дополнительно связан с ним отношением happens-before (write hb read). Если же volatile убрать, то никаких гарантий на то, что будет получено в результате чтения - не будет, это будет чтение по data race. И программа станет некорректно синхронизированной, в отличие от текущего случая с volatile, когда программа синхронизирована корректно. Или я не прав, и действительно разницы нет ?

    ОтветитьУдалить