Сериализация объектов: ни одно состояние потока не может быть задействовано, верно? - PullRequest
8 голосов
/ 08 октября 2008

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

Существуют и другие решения, в которых вы работаете с активными объектами, где к некоторым объектам прикреплен поток пользовательского уровня. И, таким образом, счетчик программы, содержимое регистра и содержимое стека внезапно становятся частью состояния программы. Насколько я вижу, не существует хорошего способа сериализации таких вещей на диск в произвольный момент времени. Потоки должны парковаться самостоятельно в каком-то особом состоянии, где счетчик программ и др. Ничего не представляет, и, таким образом, в основном «сохранять» свое состояние конечного автомата выполнения в явном состоянии объекта.

Я рассмотрел ряд библиотек сериализации, и, насколько я могу судить, это универсальное свойство.

Основной вопрос такой: Или это на самом деле не так? Существуют ли решения для сохранения / восстановления, которые могут включать состояние потока, с точки зрения того, где в его коде выполняется поток?

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

Некоторые вопросы прояснили, что я недостаточно ясно объяснил идею о том, как мы делаем вещи. Мы работаем над системой симуляторов, с очень строгими правилами для запуска кода внутри нее разрешено писать. В частности, мы полностью разделяем конструкцию объекта и его состояние. Указатели на функции интерфейса воссоздаются каждый раз при настройке системы и не являются частью состояния. Состояние состоит только из определенных назначенных «атрибутов», каждый из которых имеет определенную функцию get / set, которая преобразует между внутренним представлением времени выполнения и представлением хранилища. Для указателей между объектами все они преобразуются в имена. Таким образом, в нашем проекте объект может выглядеть следующим образом:

Object foo {
  value1: 0xff00ff00;
  value2: 0x00ffeedd;
  next_guy_in_chain: bar;
}

Object bar {
  next_guy_in_chain: null;
}

Связанные списки на самом деле никогда не присутствуют в структуре симуляции, каждый объект представляет какую-то аппаратную единицу.

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

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

Обновление, октябрь 2009 г .: Документ, связанный с этим, был опубликован на конференции FDL в 2009 г., см. этот документ о контрольных точках и SystemC.

Ответы [ 7 ]

2 голосов
/ 08 октября 2008

Я не думаю, что сериализация только "некоторых потоков" программы может работать, так как у вас возникнут проблемы с синхронизацией (некоторые проблемы описаны здесь http://java.sun.com/j2se/1.3/docs/guide/misc/threadPrimitiveDeprecation.html). Таким образом, сохранение всей вашей программы - единственный жизнеспособный способ получить согласованное состояние.

То, на что вы могли бы обратить внимание, это ортогональная настойчивость. Существует несколько прототипов:

http://research.sun.com/forest/COM.Sun.Labs.Forest.doc.external_www.PJava.main.html

http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.17.7429

Но ни один из них больше не поддерживается или приобрел большую привлекательность (afaik). Я думаю, контрольно-пропускные пункты не лучшее решение в конце концов. В моем собственном проекте http://www.siebengeisslein.org я пытаюсь использовать легкие транзакции для отправки события, чтобы не требовалось поддерживать состояние потока (так как в конце транзакции стек вызовов снова пуст, и если операция в середине транзакции останавливается, все откатывается, поэтому стек вызовов также имеет значение). Вы, вероятно, можете реализовать нечто подобное с любой OODBMS.

Еще один способ взглянуть на вещи - это продолжения (http://en.wikipedia.org/wiki/Continuation, http://jauvm.blogspot.com/).. Это способ приостановить выполнение в определенных местах кода (но они не обязательно сохраняют состояние потока).

Я надеюсь, что это даст вам некоторые отправные точки (но нет никакого готового к использованию решения для этого afaik).

РЕДАКТИРОВАТЬ: После прочтения ваших разъяснений: вы должны обязательно заглянуть в OODBMS. Отправляйте каждое событие в отдельной транзакции и не обращайте внимания на потоки.

1 голос
/ 08 октября 2008

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

1 голос
/ 08 октября 2008

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

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

0 голосов
/ 09 октября 2008

Нечто подобное было предложено для Java в JSR 323:

http://tech.puredanger.com/2008/01/09/strong-mobility-for-java/

, но не был принят как слишком теоретический:

http://tech.puredanger.com/2008/01/24/jcp-votes-down-jsr-323/

Если вы перейдете по ссылкам, то сможете найти интересные исследования по этой проблеме.

0 голосов
/ 08 октября 2008

Я считаю, что состояние потока - это деталь реализации, которая, вероятно, не подходит для сериализации. Вы хотите сохранить состояние своих объектов - не обязательно, чтобы они были такими, какие они есть.

В качестве примера того, почему вы хотите использовать этот подход, рассмотрите возможность безударного обновления. Если вы используете версию N своего приложения и хотите обновить ее до версии N + 1, вы можете сделать это, используя сериализацию объектов. Однако потоки версии N + 1 не будут отличаться от потоков версии N.

0 голосов
/ 08 октября 2008

Похоже, вы хотите иметь замыкание в C ++. Как вы указали, в язык не встроен механизм, позволяющий вам это делать. Насколько я знаю, это в принципе невозможно сделать абсолютно общим образом. В общем, это трудно сделать на языке, в котором нет виртуальной машины. Вы можете немного подделать его, выполнив что-то, как вы предложили, в основном, создав объект замыкания, который поддерживает среду / состояние выполнения. Затем, имея эту сериализацию, когда она находится в известном состоянии.

У вас также могут возникнуть проблемы с указателями на функции. Функции могут загружаться по разным адресам памяти при каждой загрузке.

0 голосов
/ 08 октября 2008

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

Вы не можете гарантировать, что указатель на какое-либо расположение виртуальной памяти снова будет указывать на то же расположение виртуальной памяти (за исключением таких свойств, как heap-begin / end, stack-begin), поскольку для программы выбор операционных систем для виртуальной памяти является неопределенным. Страницы, которые вы запрашиваете у ОС через sbrk или интерфейсы более высокого уровня, такие как malloc, начнутся где угодно.

Лучше:

  • Код очищает и проверяет ваш дизайн: какие свойства состояния являются его частью?
  • Не используйте такой низкоуровневый язык, потому что затраты на создание того, что вы пытаетесь сделать, не стоят результатов.
  • Если вам нужно использовать C, подумайте о том, как сделать вашу жизнь максимально простой (рассмотрите оператор offsetof, и структуры свойств имеют такие свойства, как первый член, начинающийся со смещения 0).

Я подозреваю, , что вы хотите сократить время разработки, необходимое для сериализации / десериализации определенных структур данных , таких как связанные списки. Будьте уверены, то, что вы пытаетесь сделать, не тривиально, и это намного больше работы . Если вы настаиваете на этом, рассмотрите код управления памятью вашей операционной системы и механизмы подкачки ОС. ; -)

РЕДАКТИРОВАТЬ из-за добавленного вопроса: проект, который вы заявляете, звучит как некий конечный автомат; свойства объекта устанавливаются так, чтобы они были сериализуемыми, указатели функций могли быть восстановлены.

Во-первых, относительно состояний потоков в объектах: это имеет значение только в том случае, если могут быть типичные проблемы параллельного программирования, такие как условия гонки и т. Д. Если это так, вам нужны функции синхронизации потоков, такие как мьютексы, семафоры и т. д. Затем вы можете в любое время получить доступ к свойствам для сериализации / десериализации и обеспечения безопасности.

Во-вторых, в отношении настройки объекта: выглядит круто, не уверен, что у вас есть двоичное или другое представление объекта. Предполагая двоичный код: вы можете легко их сериализовать, если можете представлять фактические структуры в памяти (что немного накладывает расходы на кодирование). Вставьте какое-то значение идентификатора класса в начале объектов и получите таблицу поиска, которая указывает на фактический наряд . Посмотрите на первые байты sizeof (id) и вы знаете, какая у вас структура. Тогда вы узнаете, какая структура там лежит.

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

РЕДАКТИРОВАТЬ из-за жирного основного вопроса: -) Нет, их нет; не для C.

...