Как происходит переключение контекста потока? - PullRequest
12 голосов
/ 31 декабря 2010

Как я понимаю, при переключении контекста процесса 'резервное копирование' ОС осуществляется регистрами и указателем команд (также является частью регистра).

Но в случае переключения между потоками в процессе ОС возьмет резервную копию полной памяти регистра и стека?

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

Ответы [ 6 ]

7 голосов
/ 31 декабря 2010

если ключевое слово volatile в Java имеет какое-либо значение в случае одноядерных процессоров.

Оптимизация, используемая компилятором jit, может вызвать непредвиденное поведение.

static boolean foo = true;

public void bar(){
   while(foo){
     //doSomething
     //do not modify foo in here
   }
}

это может быть оптимизировано, так как foo не изменяется внутри цикла.

public void bar(){
    while(true){
     //Now this loop never ends
     //changes to foo are ignored
    }
}

make foo volatile сообщит компилятору jit, что foo может быть изменен другим потоком, и доступ к нему не должен быть оптимизирован.

Это допустимое поведение, поскольку межпотоковый доступ гарантированно работает только с

  • изменчивые и синхронизированные ключевые слова
  • классы, которые утверждают, что они являются потокобезопасными (например, java.util.concurrent. *)

Обновление

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

4 голосов
/ 31 декабря 2010

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

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

3 голосов
/ 31 декабря 2010

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

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

2 голосов
/ 31 декабря 2010

Проверьте JSR 133 и, в частности, раздел с пометкой «Что делает летучее?»

Летучие поля - это специальные поля которые используются для общения государства между нитями. Каждое чтение volatile будет видеть последнюю запись в что изменчиво любой нитью; в эффект, они обозначены программист как поля для которых он никогда не приемлемо видеть "несвежую" значение в результате кэширования или переназначения.

Это полезное введение и описание того, как volatile работает с моделью памяти JVM.

2 голосов
/ 31 декабря 2010

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

0 голосов
/ 02 января 2011

Я знаю, что делает volatile, но я пытаюсь понять, почему это необходимо. Позвольте мне уточнить.

Как уже упоминалось выше, josefx. Если у нас есть что-то вроде ниже: -

while(run) {
 //do something but don't modify run
}

Если какой-то другой поток превратит run в false, тогда цикл while никогда не закончится. Как уже упоминал Ювал А, во время переключения контекста потока резервное копирование регистров тоже происходит. Поэтому я думаю, что это работает так.

Если какой-либо поток изменяет значение run, значение будет изменено только в регистре. Во время переключения контекста Java не будет синхронизировать это значение регистра с копией в ОЗУ, если это явно не помечено как volatile. Таким образом, каждый поток будет работать со своей версией run. Но эта концепция не применяется к не примитивам и примитивам, таким как целочисленные и т. Д., Которые не помещаются в регистр как единое целое, заставляя их синхронизироваться с копией RAM.

...