ATL Objects Are Not Thread-safe? 
Author Message
 ATL Objects Are Not Thread-safe?

Hello All,

Perhaps many of you have noticed this before, the ATL implements
AddRef and Release like the following, where Increment and Decrement
are expanded to InterlockedXXX functions in multithreaded versions.

        ULONG InternalAddRef()
        {
                ATLASSERT(m_dwRef != -1L);
                return _ThreadModel::Increment(&m_dwRef);
        }
        ULONG InternalRelease()
        {
                ATLASSERT(m_dwRef > 0);
                return _ThreadModel::Decrement(&m_dwRef);
        }

        STDMETHOD_(ULONG, Release)()
        {
                ULONG l = InternalRelease();
                if (l == 0)
                        delete this;
                return l;
        }

        STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();}

However, if two or more threads are accessing a shared object, it is
possible for two threads calling Addref and Release in the following
order:
T1                         T2
AddRef()
                           Release()
                           InternalRelease()
InternalAddRef()
                           delete this

and T1 will get an invalid pointer.

Some people argue this situation is against the rules of COM, but I
don't think so. Please consider the following example:

class SharedObject
{
    IMyComObject *po;

    void Get(IMyComObject **pp)
    {
        *pp=po;
        if(*pp)
           (*pp)->AddRef();
    }
    void Set(IMyComObject *p)
    {    if(p)
             p->AddRef();
         if(po)
           po->Release();
         po=p;
    }

Quote:
};

And have two threads call Get and Set on the same SharedObject
samultaneously, like the following:

SharedObject o;

T1:                                   T2
IMyComObject *p1;                     IMyComObject *p2; ...//p2 to a
new object
o.Get(&o);                            o.Set(p2);

Could anybody tell me what I am missing? Why this is not causing many
problems?

Thanks,
Geoffrey



Fri, 29 Oct 2004 23:29:07 GMT  
 ATL Objects Are Not Thread-safe?

Quote:
> Hello All,

> Perhaps many of you have noticed this before, the ATL implements
> AddRef and Release like the following, where Increment and Decrement
> are expanded to InterlockedXXX functions in multithreaded versions.

> ULONG InternalAddRef()
> {
> ATLASSERT(m_dwRef != -1L);
> return _ThreadModel::Increment(&m_dwRef);
> }
> ULONG InternalRelease()
> {
> ATLASSERT(m_dwRef > 0);
> return _ThreadModel::Decrement(&m_dwRef);
> }

> STDMETHOD_(ULONG, Release)()
> {
> ULONG l = InternalRelease();
> if (l == 0)
> delete this;
> return l;
> }

> STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();}

> However, if two or more threads are accessing a shared object, it is
> possible for two threads calling Addref and Release in the following
> order:
> T1                         T2
> AddRef()
>                            Release()
>                            InternalRelease()
> InternalAddRef()
>                            delete this

> and T1 will get an invalid pointer.

> Some people argue this situation is against the rules of COM, but I
> don't think so. Please consider the following example:

> class SharedObject
> {
>     IMyComObject *po;

>     void Get(IMyComObject **pp)
>     {
>         *pp=po;
>         if(*pp)
>            (*pp)->AddRef();
>     }
>     void Set(IMyComObject *p)
>     {    if(p)
>              p->AddRef();
>          if(po)
>            po->Release();
>          po=p;
>     }

> };

> And have two threads call Get and Set on the same SharedObject
> samultaneously, like the following:

> SharedObject o;

> T1:                                   T2
> IMyComObject *p1;                     IMyComObject *p2; ...//p2 to a
> new object
> o.Get(&o);                            o.Set(p2);

> Could anybody tell me what I am missing? Why this is not causing many
> problems?

As long as you stick to the rules of COM, ATL's implementation of
AddRef/Release is safe. Why? If two threads both access a shared (COM)
object, they both hold a reference to the object and therefor the object's
reference count is at least two and it will not try to delete itself.

But there really is a problem in your example. But the problem is not the
COM object but your implementation is not thread-safe. Look at
SharedObject::Set. Two threads may modify the same object simultaniously.
That's begging for trouble.

Regards
    Heinz



Sat, 30 Oct 2004 00:34:38 GMT  
 ATL Objects Are Not Thread-safe?
Your po member interface pointer must be AddRef-ed. It must
also be protected for concurrent access. It seems you AddRef-ed
it correctly. but a mutex/critical section is missing. As long as it
is AddRef-ed, a secondary AddRef/Release is not going to
corrupt the object state. Keep in mind the assignment includes
the previous Release and the subsequent AddRef...

--
=====================================
Alexander Nickolov
Microsoft MVP [VC], MCSD

MVP VC FAQ: http://www.mvps.org/vcfaq
=====================================

Quote:

> Hello All,

> Perhaps many of you have noticed this before, the ATL implements
> AddRef and Release like the following, where Increment and Decrement
> are expanded to InterlockedXXX functions in multithreaded versions.

> ULONG InternalAddRef()
> {
> ATLASSERT(m_dwRef != -1L);
> return _ThreadModel::Increment(&m_dwRef);
> }
> ULONG InternalRelease()
> {
> ATLASSERT(m_dwRef > 0);
> return _ThreadModel::Decrement(&m_dwRef);
> }

> STDMETHOD_(ULONG, Release)()
> {
> ULONG l = InternalRelease();
> if (l == 0)
> delete this;
> return l;
> }

> STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();}

> However, if two or more threads are accessing a shared object, it is
> possible for two threads calling Addref and Release in the following
> order:
> T1                         T2
> AddRef()
>                            Release()
>                            InternalRelease()
> InternalAddRef()
>                            delete this

> and T1 will get an invalid pointer.

> Some people argue this situation is against the rules of COM, but I
> don't think so. Please consider the following example:

> class SharedObject
> {
>     IMyComObject *po;

>     void Get(IMyComObject **pp)
>     {
>         *pp=po;
>         if(*pp)
>            (*pp)->AddRef();
>     }
>     void Set(IMyComObject *p)
>     {    if(p)
>              p->AddRef();
>          if(po)
>            po->Release();
>          po=p;
>     }

> };

> And have two threads call Get and Set on the same SharedObject
> samultaneously, like the following:

> SharedObject o;

> T1:                                   T2
> IMyComObject *p1;                     IMyComObject *p2; ...//p2 to a
> new object
> o.Get(&o);                            o.Set(p2);

> Could anybody tell me what I am missing? Why this is not causing many
> problems?

> Thanks,
> Geoffrey



Sat, 30 Oct 2004 05:46:37 GMT  
 
 [ 3 post ] 

 Relevant Pages 

1. Is ATL's CComPtr not thread safe ?!!

2. Why OleDbCommand objects are not thread safe?

3. Call to local static object constructor not thread-safe

4. Creating thread-neutral object from ATL Object wizard

5. When to keep an object thread-safe?

6. Is MFC 4.2 thread safe in object level?

7. Apartment thread is not safe ?

8. _endthread() Safe to call if not in thread?

9. sprintf not thread safe

10. Why is function static singleton not thread-safe?

11. CRichEditCtrl - Not thread safe?

12. Is NetShareEnum NOT thread-safe

 

 
Powered by phpBB® Forum Software