Подтвердить что ты не робот

Как реализовать поточный подсчет ссылок в С++

Как вы внедряете эффективную и надежную систему подсчета ссылок с поддержкой потоков на процессорах X86 на языке программирования С++?

Я всегда сталкиваюсь с проблемой, что критические операции не атомные, а доступные операции блокировки X86 недостаточно для реализации системы подсчета ссылок.

В следующей статье рассматривается этот раздел, но для этого требуются специальные инструкции CPU:

http://www.ddj.com/architect/184401888

4b9b3361

Ответ 1

В настоящее время вы можете использовать интеллектуальный указатель Boost/TR1 shared_ptr < > smart, чтобы поддерживать ссылки на подсчитанные ссылки.

Прекрасно работает; нет суеты, не мусс. Класс shared_ptr < > заботится обо всех блокировках, необходимых для пересчета.

Ответ 2

В VС++ вы можете использовать _ InterlockedCompareExchange.

do
   read the count
   perform mathematical operation
   interlockedcompareexchange( destination, updated count, old count)
until the interlockedcompareexchange returns the success code.

На других платформах/компиляторах используйте соответствующую функцию для инструкции LOCK CMPXCHG, которую предоставляет MS _InterlockedCompareExchange.

Ответ 3

Строго говоря, вам нужно подождать, пока С++ 0x не сможет писать потокобезопасный код в чистом С++.

В настоящее время вы можете использовать Posix или создавать собственные независимые от платформы обертки вокруг сравнения и свопинга и/или блокировки приращения/уменьшения.

Ответ 4

Win32 InterlockedIncrementAcquire и InterlockedDecrementRelease (если вы хотите быть в безопасности и заботиться о платформах с возможным переупорядочением, следовательно, вам необходимо одновременно устранить барьеры памяти) или InterlockedIncrement и InterlockedDecrement (если вы уверены, что останетесь x86), атомный и будет выполнять эту работу.

Тем не менее, Boost/TR1 shared_ptr < > будет обрабатывать все это для вас, поэтому, если вам не нужно реализовать его самостоятельно, вы, вероятно, сделаете все возможное, чтобы придерживаться его.

Ответ 5

Имейте в виду, что блокировка очень дорогая, и это происходит каждый раз, когда вы обмениваетесь объектами между умными указателями - даже когда объект в настоящее время принадлежит одному потоку (библиотека интеллектуального указателя этого не знает).

Учитывая это, может быть применено правило действия (я рад, что его исправили!)

Если к вам относятся следующие вещи:

  • У вас есть сложные структуры данных, которые трудно было бы написать деструкторы для (или где семантика значения стиля STL была бы неуместной, по дизайну), поэтому вам нужны интеллектуальные указатели, чтобы сделать это за вас, и
  • Вы используете несколько потоков, которые делят эти объекты, и
  • Вы заботитесь о производительности, а также о правильности.

... тогда фактическая сборка мусора может быть лучшим выбором. Хотя GC имеет плохую репутацию для производительности, все это относительное. Я считаю, что он очень хорошо согласуется с блокировкой интеллектуальных указателей. Это была важная часть того, почему команда CLR выбрала истинный GC вместо чего-то, используя подсчет ссылок. См. в этой статье, в частности, это резкое сравнение того, что означает ссылочное назначение, если вы считаете, что происходит:

нет ref-counting:

a = b;

ref counting:

if (a != null)
    if (InterlockedDecrement(ref a.m_ref) == 0)
            a.FinalRelease();

if (b != null)
    InterlockedIncrement(ref b.m_ref);

a = b;

Ответ 6

Если сама инструкция не является атомарной, вам нужно сделать раздел кода, который обновляет соответствующую переменную в критической секции.

i.e. Вам нужно запретить другим потокам входить в этот раздел кода, используя некоторую схему блокировки. Конечно, блокировки должны быть атомарными, но вы можете найти механизм атомной блокировки в классе pthread_mutex.

Вопрос об эффективности: библиотека pthread настолько эффективна, насколько это возможно, и по-прежнему гарантирует, что блокировка мьютекса является атомарной для вашей ОС.

Это дорого: возможно. Но для всего, что требует гарантии, есть стоимость.

Ответ 7

Этот конкретный код, размещенный в этой статье ddj, добавляет дополнительную сложность для учета ошибок при использовании интеллектуальных указателей.

В частности, если вы не можете гарантировать, что интеллектуальный указатель не изменится при назначении другому интеллектуальному указателю, вы делаете это неправильно или делаете что-то очень ненадежное для начала. Если интеллектуальный указатель может измениться при назначении другому интеллектуальному указателю, это означает, что код, выполняющий присваивание, не владеет интеллектуальным указателем, который с самого начала подозревается.