понедельник, 9 июля 2007 г.

ООП в многопоточной среде: Введение

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

Методы, связанные с классом хорошо справляются со своей задачей, но когда мы используем ООП в многопоточной среде, то помимо классов и объектов появляются еще и потоки. В языке С++ нет такого понятия, как поток, а следовательно компилятор не делает каких-либо проверок относительно них. И ситуация начинает повторяться. Хоть изменение состояния и локализовано в методах, но сказать когда и в каком потоке будет выполняться этот метод в общем случае невозможно. Потоки как бы проникают сквозь барьер инкапсуляции, и это может разрушить состояние объекта. В теории компьютерных наук такая ситуация называется гонками – ситуация, в которой два (и более) процесса считывают или записывают данные одновременно, а конечный результат зависит от того, какой из них был первым.

Чтобы избежать такой ситуации в Java, например, есть такой атрибут для методов как synchronized, а в языках С++ и Delphi таких атрибутов нет, и поэтому, необходимо код каждого публичного метода защищать критической секцией.
Мой опыт создания ядра библиотеки act-o говорит о том, что это очень плохая идея – писать программы в стиле ООП доступном на С++, защищая публичные методы критическими секциями. Потому, что почти сразу я столкнулся с явлением взаимоблокировки и разобраться, что и почему блокируется, было просто невозможно. Я отказался от ООП в пользу процедурного стиля.

Один из возможных способов избежать вышеописанных проблем – это вернуться к первоначальной концепции ООП, предложенной Аланом Кеем.
Алан Кей – это человек, который создал язык программирования Smalltalk, и ввел термин «объектно-ориентированный». Тогда он вкладывал в этот термин три основных идее:
  • Объект – базовая единица объектно-ориентированной системы.
  • Объекты могут обладать состоянием.
  • Посылка сообщений – единственный способ обмена информацией между объектами.
Для нас сейчас важен последний пункт – «посылка сообщений». Если организовать взаимодействие между объектами с помощью сообщений, а не через вызовы методов (как в C++), то удастся решить проблемы с инкапсуляцией и гонками. Только необходим настоящий обмен сообщениями – асинхронный, посредством организации очереди.

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

Все это краткое описание тех идей, на основе которых построена библиотека act-o, и именно такой механизм организации взаимодействия между объектами она предоставляет.

В недалеком будущем я опубликую небольшое исследование об истории ООП и о том, как оно от определения, данного Аланом Кеем, превратилось в то, чем оно является сейчас. Похоже, что модель актеров – это начальная идея ООП, но в новой обертке.
Также расскажу о таком понятии как Inversion of Control (IoC) и почему оно тоже может представлять проблему не только в многопоточном ООП, но и в классическом.
Оставайтесь на связи… :-)

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