Hello, Cruser!
You wrote on Tue, 03 Jul 2007 16:25:38 GMT:
C> Если есть набор классов, вызовы методов которых должны быть C> внутренне синхронизированы, то как обычно делают это в сложных C> проектах:
C> 1) Просто в каждый метод добавить семафор C> 2) Организовать очередь сообщений (вызовов).
C> Первый вариант вроде проще, но при добавлении нового метода можно C> забыть про семафор.
Методы должны быть синхронизированы на что — на свой объект?
Если язык не поддерживает более выскоуровневую модель, то да: семафоры/мониторы и ручная синхронизация. Но, например, в Java механизм мониторов встроен непосредственно в язык: ты указываешь, что метод синхронизированный, и безопасный конкурентный доступ обеспечивается автоматически.
Если очень заботит проблема забыть войти или выйти из монитора, то для контроля можно использовать прокси-объекты или AOP.
Если есть набор классов, вызовы методов которых должны быть внутренне синхронизированы, то как обычно делают это в сложных проектах:
1) Просто в каждый метод добавить семафор
2) Организовать очередь сообщений (вызовов).
Первый вариант вроде проще, но при добавлении нового метода можно забыть про семафор.
Второй вариант элегантнее, но имеет минусы: надо как-то организовывать возврат результатов, на каждую функцию заводить структуру для её параметров, а также код сообщения.
Здравствуйте, YК, Вы писали:
YК>Если язык не поддерживает более выскоуровневую модель, то да: семафоры/мониторы и ручная синхронизация. Но, например, в Java механизм мониторов встроен непосредственно в язык: ты указываешь, что метод синхронизированный, и безопасный конкурентный доступ обеспечивается автоматически.
Хотел бы добавить, что он безопасный только с точки зрения взаимоисключающего доступа, он гонок и дедлоков такой подход (навешивание атрибута syncronized) разумеется не спасет.
Здравствуйте, Cruser, Вы писали:
YК>>Если очень заботит проблема забыть войти или выйти из монитора, то для контроля можно использовать прокси-объекты или AOP.
C> Язык С++. Да, прокси вроде удобнее.
C> Если есть набор классов, вызовы методов которых должны быть внутренне синхронизированы, то как обычно делают это в сложных проектах:
C>1) Просто в каждый метод добавить семафор C>2) Организовать очередь сообщений (вызовов).
C> Первый вариант вроде проще, но при добавлении нового метода можно забыть про семафор. C> Второй вариант элегантнее, но имеет минусы: надо как-то организовывать возврат результатов, на каждую функцию заводить структуру для её параметров, а также код сообщения.
Второй вариант бессмысленный, т.к. не имеет никаких плюсов, только ряд серьезных минусов.
C>3) ?
3) Элиминировать разделение данных
4) Реализовать lock-free reader pattern или full-fledged lock-free
з.ы. в первом пункте использовать надо, естественно, не семафоры, а user-space mutex подходящего типа.
Здравствуйте, Didro, Вы писали:
D>Здравствуйте, YК, Вы писали:
YК>>Если язык не поддерживает более выскоуровневую модель, то да: семафоры/мониторы и ручная синхронизация. Но, например, в Java механизм мониторов встроен непосредственно в язык: ты указываешь, что метод синхронизированный, и безопасный конкурентный доступ обеспечивается автоматически.
D>Хотел бы добавить, что он безопасный только с точки зрения взаимоисключающего доступа, он гонок и дедлоков такой подход (навешивание атрибута syncronized) разумеется не спасет.
Насчет гонок — мимо кассы. Java Language Specification гарантирует отсутсвие гонок при использовании synchronized.
Two actions can be ordered by a happens-before relationship. If one action happens-before another, then the first is visible to and ordered before the second.
If we have two actions x and y, we write hb(x, y) to indicate that x happens-before y.
If x and y are actions of the same thread and x comes before y in program order, then hb(x, y).
There is a happens-before edge from the end of a constructor of an object to the start of a finalizer (§12.6) for that object. If an action x synchronizes-with a following action y, then we also have hb(x, y).
If hb(x, y) and hb(y, z), then hb(x, z).
We say that a read r of a variable v is allowed to observe a write w to v if, in the happens-before partial order of the execution trace:
r is not ordered before w (i.e., it is not the case that hb(r, w), and
there is no intervening write w' to v (i.e., no write w' to v such that hb(w, w') and hb(w', r).
Informally, a read r is allowed to see the result of a write w if there is no happens-before ordering to prevent that read.
C>1) Просто в каждый метод добавить семафор C>2) Организовать очередь сообщений (вызовов).
Каков внешний интерфейс к этой подсистеме?
Если там устроят только блокирующие вызовы — т.е. нить позвала этот вызов и там в нем заблокировалась, возможно, надолго — то 1 будет достаточно вполне. Очередь там все равно будет — очередь ожидающих нитей в кернеле
2, на мой взгляд, имеет смысл, только если речь идет об overlapped, asynchronous интерфейсу к этой подсистеме. То есть — вызов дает задание, не блокируясь, задание начинает как-то выполняться, и вызывающей стороне доступна на него ссылка. Через ссылку можно "узнать, как дела" — т.е. дождаться завершения и узнать результат выполнения завершенного задания.
Если такие навороты — как в NTшной подсистеме ввода-вывода — хочется иметь, то вот тогда надо делать 2. Иначе я не вижу никакого толку в 2, а усложнение там весьма заметно, нужен, например, еще класс объектов "задание", механизмы ожидания их завершений и прочее такое.
Здравствуйте, Cruser, Вы писали:
C>1) Просто в каждый метод добавить семафор
C> Первый вариант вроде проще, но при добавлении нового метода можно забыть про семафор.
Попробуйте aspect-oriented составляющую, чтобы облегчить себе жизнь