Вчера выловил в SObjectizer серьезную ошибку, которая сидела в нем, наверное с незапамятных времен. Проявлялась она в ситуации, когда агент завершал обработку своего собственного сообщения, а в этот момент его на другой нити дерегистрировали. Суть в том, что после выхода из обработчика события для данной заявки уменьшались счетчики ссылок на саму заявку, на экземпляр сообщения и на агента. И вот, когда все счетчики ссылок обнулялись и оставалось только вызвать функцию уничтожения объекта-сообщения, как управление передавалось другой нити. Другая нить дерегистрировала агента и, поскольку ссылок на этого агента не оставалось, то агент и все его SObjectizer-овские внутренности уничтожались. Потом управление передавалось обратно первой нити, которая должна была уничтожить объект-сообщение. Но это уничтожение выполнялось с помощью вспомогательного объекта с описанием сообщения агента. А этот объект уже оказывался разрушенным вместе с самим агентом. Поэтому происходило обращение к повисшему указателю со вполне ожидаемыми последствиями.
Ошибки в многопоточных программах начинают напоминать мне важный закон, который был выведен физиками-экспериментаторами:
Все, что может сломаться, сломается обязательно. Все, что не может сломаться, сломается тоже.
Так и здесь. Вероятность возникновения такой последовательности событий, да еще в тот мизерный зазор по времени между обнулением счетчика ссылок и вызовом деструктора объекта, ну очень мала (как мне кажется). И тем, не менее, она воплотилась. Да еще в весьма важном проекте, который работает в режиме 24x7 под постоянно возрастающей нагрузкой.
PS. Я когда-то выдвигал в качестве недостатка языка C++ отсутствие в нем stack trace “из коробки”. Чтобы при сбое программы сама стандартная библиотека C++ выдавала точное место сбоя. Самое смешное, что в данном случае stack trace совершенно не помогал (я его получил таки с помощью StackWalker-а). Поскольку по stack trace не было ясно, что именно провоцировало сбой – долгое время я вообще грешил, что данная ошибка “наведенная”, что сбой в этом месте является порчей памяти где-то в прикладной логике.
Комментариев нет:
Отправить комментарий