я рассуждал над вопросом, и пришёл к выводу, что если сделать проверку и сравнение атомарной операцией, то делу как раз таки поможешь, однако, при одном условии: если нет никаких "слабых" ссылок на объект, то есть, все, кто имеют ссылку на объект, её имеют. То есть, если количество ссылок доходит до нуля, то никто уже не может вызвать для данного объекта _AddRef, если только не было мест, которые ссылку имели, но _AddRef не делали, так что атомарность сравнения и уничтожения проблему решает, кроме, как я уже сказал, случаев, когда нужно, чтобы были так называемые слабые ссылки, которые есть, но _AddRef не делали
Что меня во всей этой системе подсчёта ссылок интересует, так это то, что если делать так, как я говорю, то есть, делать эту самую атомарность для двух операций, то функции interlockedincrement и interlockeddecrement тут уже не подойдут, и нужно будет на каждый объект создавать критическую секцию или мьютекс. Не уверен, отличаются ли эти два объекта на уровне операционной системы. Вот как бы так сделать, чтобы найти все объекты, которые используются только из одного потока, и для них не создавать критическую секцию, да и interlocked-функции для них можно не использовать, так как если объект используется только из одного потока, то вызовы никогда не пересекутся. А для всех объектов, которые могут использоваться из разных потоков, включить использование критических секций. Тут возможны принципиально несколько подходов:
1. Включить критические секции для всех ссылочноподсчётных классов, и позже просто стараться использовать их по минимуму, то есть, в местах, где это очень хочется, а все остальные классы по возможности оставить обычными, то есть, без подсчёта ссылок, чтобы критические секции в каждом объекте не замедляли работу программы
2. Контролировать тип ссылочноподсчётного объекта вручную: например, чтобы в конструкторе был аргумент threadSafe, если указываешь True, то критическая секция используется, иначе не используется. В этом подходе придётся много думать, так как придётся заранее догадаться, будет данный объект использоваться из нескольких потоков, или не будет.
3. Сделать какой-то статический анализатор кода, который будет догадываться по коду, какие ссылочноподсчётные объекты надо синхронизировать, а какие не надо, но это очень сложно сделать такой анализатор
4. Сделать, чтобы объект при каждом вызове AddRef запоминал CurrentThreadId, хранил предыдущий ThreadID, и каждый раз их сравнивал, и как только они впервые не совпадут, так сразу включал критическую секцию, но это дурацкий какой-то подход потому, что сложно сказать, будет ли он работать на 100 % или нет, или же придётся присваивание PreviousThreadId := CurrentThreadId и сравнение тоже синхронизировать, тогда будет ещё хуже, критических секций будет ещё больше
5. А что если сделать, чтобы на все экземпляры одного класса была одна критическая секция? Или вообще одна на всех. Тогда будет выигрыш по памяти, но проигрыш по производительности. Дурацкий подход. Но в принципе можно попробовать
В общем, всё надо пробовать и тестировать, в том числе и COM-интерфейсы
Кто-то тут написал, что COM-интерфейсы тут ни при чём, а я говорю, что причём. В том и дело, что в FPC два режима интерфейсов: CORBA и COM. А какого-то абстрактного "просто интерфейса" на уровне языка нет. Для интерфейсов CORBA подсчёт ссылок не делается. Остаются интерфейсы COM.
Добавлено спустя 1 минуту 54 секунды:Вот по поводу интерфейсов: только что прочитал
- Код: Выделить всё
- COM, CORBA and raw interfaces support
здесь:
http://sourceforge.net/projects/freepas ... n32/2.6.4/Вот что они хотели этим сказать? не слышал ничего про "raw interfaces". Это какая-то новая фича щито ли?