В собственной системе без более высокой мощности (например, ВМ), способной выполнять сборку мусора, производительность и сложность не будут намного выше, чем при подсчете ссылок.
Вы правы, подсчет ссылок может быть сложным - не только приращение и уменьшение должно быть атомарным, но вы должны убедиться, что объект не может быть удален из-под вас, прежде чем вы сможете увеличить его. Таким образом, если вы храните счетчик ссылок внутри объекта, вам придется каким-то образом избегать гонки, которая возникает между моментом, когда вы читаете указатель на объект из кэша, и удается увеличивать указатель.
Если ваша структура является стандартным контейнером, который еще не является потокобезопасным, вам также придется защитить контейнер от неподдерживаемого одновременного доступа. Эта защита может прекрасно сочетаться с отсутствием условия гонки подсчета ссылок, описанного выше - если вы используете блокировку чтения-записи для защиты структуры в сочетании с атомарными приращениями счетчика ссылок в объекте, все еще удерживая блокировку чтения, вы будете защищен от любого, кто удаляет объект из-под вас, прежде чем вы получите счетчик ссылок, так как такие мутаторы должны быть «писателями».
Здесь объекты могут быть извлечены из кэша, при этом все еще имея положительный счетчик ссылок - они будут уничтожены при удалении последней невыполненной ссылки (вашим классом интеллектуальных указателей). Обычно это считается особенностью, поскольку это означает, что по крайней мере некоторый объект всегда может быть удален из кэша, но также имеет недостаток, заключающийся в том, что не существует строгого верхнего уровня для числа объектов, «живых» в памяти, поскольку подсчет ссылок позволяет объектам говорить живыми даже после того, как они покинули кеш. Приемлемо ли это для вас, зависит от ваших требований и деталей, например, как долго другие потоки могут хранить ссылки на объекты.
Если у вас нет доступа к (нестандартным) процедурам атомарного приращения, вы можете использовать мьютекс для выполнения атомарного приращения / уменьшения, хотя это может значительно увеличить стоимость как во времени, так и в пространстве на объект.
Если вы хотите стать более экзотичным (и более быстрым), вам нужно спроектировать контейнер, который сам по себе является потокобезопасным, и придумать более сложный механизм подсчета ссылок. Например, вы можете создать хеш-таблицу, в которой основной массив блоков никогда не перераспределяется, поэтому доступ к нему можно получить без блокировки. Кроме того, вы можете использовать непереносимые операции CAS (сравнить и поменять) двойной ширины в этом массиве, чтобы одновременно прочитать указатель и увеличить счетчик ссылок рядом с ним (128 бит данных в 64-битной арке), что позволяет вам избегайте гонки, упомянутой выше.
Совершенно другой путь - реализация какой-то стратегии "отложенного безопасного удаления". Здесь избегайте подсчета ссылок полностью. Вы удаляете ссылки из своего кэша, но не удаляете объекты немедленно, так как другие потоки могут все еще содержать указатели на объект. Затем, в какое-то «безопасное» время, вы удаляете объект. Конечно, дело в том, чтобы обнаружить, когда такое безопасное время существует. Базовые стратегии предусматривают сигнализацию каждого потока, когда они «входят» и «покидают» опасную зону , во время которой они могут получить доступ к кешу и хранить ссылки на содержащиеся в нем объекты. После того, как все потоки, которые находились в опасной зоне , когда объект был удален из кэша, покинули опасную зону, вы можете освободить объект, убедившись, что ссылки больше не удерживаются.
Насколько это практично, зависит от того, есть ли у вас логические точки входа и выхода в вашем приложении (многие приложения, ориентированные на запросы), и можно ли амортизировать затраты на вход и отпуск во многих кэш-памяти. доступ. Положительным моментом является отсутствие подсчета ссылок! Конечно, вам по-прежнему нужен потокобезопасный контейнер.
Вы можете найти ссылки на многие научные статьи по этой теме и некоторые практические соображения по производительности, изучив статьи, связанные здесь .