Проблемы с подсчетом ссылок CComQIPtr, используемым в потоках

#c #multithreading #com

#c #многопоточность #com

Вопрос:

У меня есть программа, которая также интенсивно использует потоки локальных ComQIPtr переменных-членов ComQIPtr , например (очень просто):

 class dummy
{
public:
 (some code)

    void calledFromThreads ()
    {
        if (m_memberVar.getType()==1)
        {
            CComQIPtr<type2> localVar(m_memberVar);
            (more code)
        }
    }

private:
    CComQIPtr<type1> m_memberVar;

}; 
  

После интенсивного использования иногда в if (m_memberVar.getType()==1) строке возникает исключение.

После отладки я вижу, что указатель указывает 0xdddddd (удаленная память), а после другого выполнения, поместив m_memberVar точку останова памяти в позицию памяти, я вижу, что она освобождается при выходе из if (m_memberVar.getType()==1) блока, при уничтожении CComQIPtr<type2> localVar(m_memberVar) .

Это, ИМХО, никогда не должно происходить теоретически, потому что, когда CComQIPtr создается, он уже создает AddRef внутренне, поэтому, Release когда CComQIPtr уничтожается, это не должно влиять на него (это 1, а затем -1), даже если есть несколько одновременных обращений к одной и той же функции, всегда есть дополнениеперед вычитанием.

Но дело в том, что это происходит (время от времени и случайным образом) и в нескольких частях кода (он используется CComQIPtr во многих частях), и я не понимаю, почему.

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

1. Вы делаете некоторые предположения, которые могут быть или не быть верными: 1) COM-объект для начала правильно реализует пересчет, 2) у вас нет какой-либо другой ошибки в вашем коде, которая неожиданно перезаписывается m_memberVar случайным образом (переполнение буфера и т. Д.), 3) dummy объект и, следовательно, его m_memberVar член, Неуничтожается во время calledFromThreads() выполнения, таким образом, освобождается m_memberVar до CComQIPtr того, как это возможно AddRef .

2. 1) Я предполагаю, что да, COM правильно реализует RefCount. 2) Я рассматривал эту возможность, но это не так: я проверил память, изменил положение объектов и т.д. 3) Объект активен в течение всего выполнения.

3. 1) пересчет осуществляют отдельные COM-объекты, а не сам COM. 2) итак, вы можете со 100% уверенностью проверить, что type1* удерживаемый указатель m_memberVar не изменяет значение при сбое? Потому что он не должен изменять значение, даже если базовый type объект уничтожен. 3) если пересчет является точным и m_memberVar не уничтожается или не повреждается, то то, что вы описываете, просто невозможно. Вам нужно будет поместить точку останова данных в удерживаемый type1* указатель и посмотреть на стек вызовов, если / когда он действительно неожиданно изменит значение.

4. Просматривая код, я вижу, что класс COM наследуется от CComSingleThreadModel вместо CComMultiThreadModel. Я думаю, что это будет проблемой…

5. codeproject.com/Articles/17837/…