пятница, 7 декабря 2007 г.

Отцы и дети или perl, fork и деструкторы

Я конечно не Тургенев Иван Сергеевич, но также кое-что попробую рассказать о взаимоотношениях отцов и детей. Рассказать не все, а лишь то, что Иван Сергеевич умышленно опустил, чтобы не уменьшать художественную ценности своего произведения излишними техническими подробностями. Скажу сразу: поскольку эта история произошла давным-давно, то некоторые детали потеряны или, наоборот, обросли некоторыми выдумками и преувеличениями, так что за 100% достоверность не ручаюсь.

А началась все тогда, когда при открытом соединении с базой данных процесс вызвал системный вызов fork, а затем с удивлением обнаружил, что база "упала". Пришлось ему звать на помощь. Вариант с базой проверили сразу: база как работала, так и продолжала работать. Пожурили процесс за ложные показания, и начали копаться в нем.

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

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

Но как быть, когда пойдем путями неведанными, дорогами не хожеными? Стали искать решение и для такого случая, когда в сторонней библиотеке нет такого замечательного атрибута как InactiveDestroy.

Как научиться управлять деструкторами? Искали, искали и наконец-то нашли в модуле POSIX вызов _exit. Этот вызов говорит: "а пошел-ка, то на ..., то есть убирай за собой сам!" Так это то, что нужно! Конечно прямо этому совету никто не последовал - кому самому все убирать охота. Обернули, то что необходимо прибрать в лексическую область видимости - пусть сборщик мусора убирается там, а после этой области прописали POSIX::_exit(0).

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

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

Второй вариант был уже описан выше и для него достаточно использовать POSIX::_exit(0), если, конечно нет InactiveDestroy. В первом же варианте надо в дочернем процессе сразу же создать копии необходимых данных из родительского.

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

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

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

Ну вот и все. Еще одна страница в отношении "отцов и детей" стала более ясной. По крайней мере в мире информационных технологий, а вот в жизни все намного сложней и одновременно проще!

Комментариев нет: