Re: Independent thread fireing events in ATL Service synchronization requirements?
From: Phil Ten (pt_at_dafweb.com)
Date: 09/17/04
- Next message: Bonj: "Initialization of default value and Persistance of ActiveX control"
- Previous message: land: "about IObjectContextInfo"
- In reply to: Alexander Nickolov: "Re: Independent thread fireing events in ATL Service synchronization requirements?"
- Next in thread: Alexander Nickolov: "Re: Independent thread fireing events in ATL Service synchronization requirements?"
- Reply: Alexander Nickolov: "Re: Independent thread fireing events in ATL Service synchronization requirements?"
- Messages sorted by: [ date ] [ thread ]
Date: Fri, 17 Sep 2004 10:44:31 +0100
Sure, I will do my best to clarify:
On one side, I start a debug build of my ATL 7 Service
in the development environment. I use
an independent thread which continuously fire
events to all client objects found in the global list.
On the other side, I use a small VBA script
(with MS Access 2002) which
create and delete my COM object also
continuously. The event handler simply writes a
line with "debug.print ..."
Everything works fine for a few seconds and
many events are correctly sent. Then, the
development environment catch an exception
and I enter in debug mode to see what is happening.
The symptom is always the same. The exception occurs in the method
below (generated by the ATL wizard) on source line:
"CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);"
Since I am in debug mode, values of variables are available:
iConnection = 0
cConnections=1
m_vec.m_ppUnk=0x00000000
m_vec.m_pUnk=0x00000000
m_vec.m_nSize=0
Since "cConnections", initialized with "=m_vec.GetSize();",
is set to "1" the state of "m_vec" must have changed
during the execution of the method. This seem in contracdiction
with one of your previous post, where you said that
the ATL code protects "m_vec" in the proxy class.
(let me know if I misunderstood your post)
-------------------------------------------------------------
template<class T>
class CProxy_IDirWatchEvents :
public IConnectionPointImpl<T, &__uuidof(_IDirWatchEvents)>
{
public:
HRESULT Fire_FileSystemNotification( BSTR FileName)
{
HRESULT hr = S_OK;
T * pThis = static_cast<T *>(this);
int cConnections = m_vec.GetSize();
for (int iConnection = 0; iConnection < cConnections; iConnection++)
{
pThis->Lock();
CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection); <<<< Exception
<<<<< !!!!!!
pThis->Unlock();
IDispatch * pConnection = static_cast<IDispatch *>(punkConnection.p);
if (pConnection)
{
CComVariant avarParams[1];
avarParams[0] = FileName; avarParams[0].vt = VT_BSTR;
DISPPARAMS params = { avarParams, NULL, 1, 0 };
hr = pConnection->Invoke(1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD,
¶ms, NULL, NULL, NULL);
}
}
return hr;
}
};
------------------------------------------------------------------
I hope the symptom is now understandable.
Thanks again for your help.
Phil. Ten.
"Alexander Nickolov" <agnickolov@mvps.org> wrote in message
news:Ob3mlXDnEHA.4056@TK2MSFTNGP09.phx.gbl...
> It didn't make much sense. If m_nSize is zero (there's no
> m_pSize), that means you have no entries in the sink array
> and hence the loop will not execute, much less crash.
> m_vec itself is not a pointer, so it cannot be NULL for sure.
> Can you state the exact problem in clear consistent terms?
> And post the proxy method for illustration perhaps?
>
> --
> =====================================
> Alexander Nickolov
> Microsoft MVP [VC], MCSD
> email: agnickolov@mvps.org
> MVP VC FAQ: http://www.mvps.org/vcfaq
> =====================================
>
> <pt@dafweb.com> wrote in message
> news:%238cc7fBnEHA.2708@TK2MSFTNGP10.phx.gbl...
> > Yes, I did lock while adding and removing objects
> > from my global list. Indeed, as I mentioned in my previous post,
> > the problem is NOT with the object itself,
> > the pointer is valid and the object is NOT gone.
> > The problem is with the variable "m_vec" which is null,
> > despite the COM object valid state.
> >
> > Please re-read my previous post for details.
> >
> > I do use a dedicated thread to fire events.
> >
> > My VBA event handler simply write a log using
> > "debug.print ...."
> >
> > Thank you for your help.
> >
> > Phil. Ten.
> >
> >
> > "Alexander Nickolov" <agnickolov@mvps.org> wrote in message
> > news:%23PSThEBnEHA.3396@tk2msftngp13.phx.gbl...
> >> Did you lock while adding and removing your objects to the list?
> >> If you did this porperly, your object cannot be gone while you
> >> are firing the events, since the lock is maintained around the entire
> >> loop. However, make sure you have a dedicated thread for
> >> event firing, and that no object is destroyed within the event
> >> handler, otherwise locking may not be sufficient (due to reentrancy).
> >>
> >> --
> >> =====================================
> >> Alexander Nickolov
> >> Microsoft MVP [VC], MCSD
> >> email: agnickolov@mvps.org
> >> MVP VC FAQ: http://www.mvps.org/vcfaq
> >> =====================================
> >>
> >> "Phil Ten" <pt@dafweb.com> wrote in message
> >> news:eTX34C%23mEHA.3428@TK2MSFTNGP11.phx.gbl...
> >> > Thank you for your post. I followed your recommandations
> >> > and made my client list a class with synchronization inside
> >> > and a lock around the entire loop.
> >> >
> >> > To test if closing the COM object while firing events is handled
> >> > correctly, I modified my external thread so it would continuously
> >> > fire events. Then using a VBA application I create and delete
> >> > the COM object also continuously.
> >> >
> >> > Most of the time it works fine, however, from time to time
> >> > I get an exception. In the debugger I could see that the
> >> > pointer on my COM object is valid (thanks to the
> >> > synchronization inside the client list class) but variable
> >> > m_vec is null (m_pSize=0, m_ppUnk=0x0000000).
> >> >
> >> > Unfortunately, the ATL code inside the CProxy_XXXX class in the
> >> > Fire_XXXXX function tries to execute
> >> >
> >> > CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);
> >> >
> >> > which fails since m_vec is NULL.
> >> >
> >> > At this point, my guess is that the lock for the COM object
> >> > pointer is not enough and that I would also need to lock
> >> > somehow the connection with the client???
> >> >
> >> > Thanks again for your help.
> >> >
> >> > Phil. Ten.
> >> >
> >> >
> >> >
> >> > "Alexander Nickolov" <agnickolov@mvps.org> wrote in message
> >> > news:eCY3dS0mEHA.3328@TK2MSFTNGP10.phx.gbl...
> >> >> You'll need synchronization for your list all right. The best place
> >> >> would be in your global class of course. E.g. instead of using
> >> >> STL list directly, wrap it in a class that exposes methods for
> >> >> your objects to call and those methods provide the necessary
> >> >> synchronization. This falls under my last comment - you need
> >> >> proper synchronization for your data. The iteration will be a
> >> >> bottleneck, however, since you need to maintain the lock around
> >> >> the entire loop notifying your objects.
> >> >>
> >> >> --
> >> >> =====================================
> >> >> Alexander Nickolov
> >> >> Microsoft MVP [VC], MCSD
> >> >> email: agnickolov@mvps.org
> >> >> MVP VC FAQ: http://www.mvps.org/vcfaq
> >> >> =====================================
> >> >>
> >> >> "Phil Ten" <pt@dafweb.com> wrote in message
> >> >> news:Or5$7gwmEHA.556@tk2msftngp13.phx.gbl...
> >> >> > Sorry, I sent the previous post by mistake before finishing it.
> >> >> >
> >> >> > Thanks again for your post. It helps but the answer to my first
> >> >> > point in my initial post is still unclear for me.
> >> >> >
> >> >> > I will rephrase it here. I currently maintain a list of all
> >> >> > active instances of my COM object by adding the pointer
> >> >> > on the object to an STL list in the constructor of the object:
> >> >> >
> >> >> > CDirWatch::CDirWatch()
> >> >> > {
> >> >> > ClientsList.insert(this);
> >> >> > }
> >> >> >
> >> >> > I remove the pointer from my list in the destructor of the
> >> >> > COM obect:
> >> >> >
> >> >> > CDirWatch::~CDirWatch()
> >> >> > {
> >> >> > ClientsList.erase(this);
> >> >> > }
> >> >> >
> >> >> > My independent thread fires event using all pointers
> >> >> > found in the list:
> >> >> >
> >> >> > CDirWatchItemList::iterator i;
> >> >> > for (i=ClientsList.begin();i!=ClientsList.end();i++)
> >> >> > {
> >> >> > (*i)->Fire_Notification(MyData);
> >> >> > }
> >> >> >
> >> >> > My questions are:
> >> >> >
> >> >> > 1) Is the COM object Constructor/Destructor a good
> >> >> > location to add/remove pointers from my global list?
> >> >> >
> >> >> > 2) Obviously, for each loop the object may have been
> >> >> > destroyed just after extracting the pointer out of my list
> >> >> > and therefore the call to "Fire_Notification" will fail
> >> >> > because the pointer is no longer valid. How could I
> >> >> > lock all existing COM instances while I loop though the
> >> >> > list and fire events?
> >> >> >
> >> >> > Thanks again for all help.
> >> >> >
> >> >> > Phil Ten
> >> >> >
> >> >> >
> >> >> > "Alexander Nickolov" <agnickolov@mvps.org> wrote in message
> >> >> > news:O0t8JIqmEHA.1652@TK2MSFTNGP09.phx.gbl...
> >> >> >> Ok, you need synchronization in the code manipulating and
> >> >> >> accessing the m_vec array of sink pointers. ATL already does
> >> >> >> this for you in two places - IConnectionPointImpl<> and the
> >> >> >> proxy class used for firing your events. If you don't deviate
> >> >> >> from these two, you don't need any extra synchronization in
> >> >> >> your code as far as firing the events. Any extra synchronization
> >> >> >> with regards to your object's internal state is entirely up to
you.
> >> >> >> I hope this answers your question.
> >> >> >>
> >> >> >> --
> >> >> >> =====================================
> >> >> >> Alexander Nickolov
> >> >> >> Microsoft MVP [VC], MCSD
> >> >> >> email: agnickolov@mvps.org
> >> >> >> MVP VC FAQ: http://www.mvps.org/vcfaq
> >> >> >> =====================================
> >> >> >>
> >> >> >> "Phil Ten" <pt@dafweb.com> wrote in message
> >> >> >> news:ut7yzHpmEHA.1652@TK2MSFTNGP09.phx.gbl...
> >> >> >> > Thank you for your post.
> >> >> >> >
> >> >> >> > I specified the free threading model for my object.
> >> >> >> >
> >> >> >> > I use ATL 7, I defined _ATL_FREE_THREADED in the
> >> >> >> > StdAfx.h file. I checked how the code is initializing, and
> >> >> >> > I could see that "CoInitializeEx(NULL, COINIT_MULTITHREADED)"
> >> >> >> > is called.
> >> >> >> >
> >> >> >> > I hope this is the information you requested.
> >> >> >> >
> >> >> >> > Thanks again for all help.
> >> >> >> >
> >> >> >> > Phil. Ten.
> >> >> >> >
> >> >> >> >
> >> >> >> > "Alexander Nickolov" <agnickolov@mvps.org> wrote in message
> >> >> >> > news:OUQfYSomEHA.4068@tk2msftngp13.phx.gbl...
> >> >> >> >> The most important question to ask first is: what is the
> >> >> >> >> threading model of your object? Depending on the answer
> >> >> >> >> you proceed completely differently.
> >> >> >> >>
> >> >> >> >> --
> >> >> >> >> =====================================
> >> >> >> >> Alexander Nickolov
> >> >> >> >> Microsoft MVP [VC], MCSD
> >> >> >> >> email: agnickolov@mvps.org
> >> >> >> >> MVP VC FAQ: http://www.mvps.org/vcfaq
> >> >> >> >> =====================================
> >> >> >> >>
> >> >> >> >> "Phil Ten" <pt@dafweb.com> wrote in message
> >> >> >> >> news:ePmX5vjmEHA.4064@TK2MSFTNGP14.phx.gbl...
> >> >> >> >> > Hello,
> >> >> >> >> >
> >> >> >> >> > I am writing an ATL service which fires events
> >> >> >> >> > from an independent thread.
> >> >> >> >> >
> >> >> >> >> > My base code to fires events seem to work correctly.
> >> >> >> >> > However, I still to need to implement synchronization
> >> >> >> >> > features to fire events only when possible. I am
> >> >> >> >> > familar with threads synchronization functions but,
> >> >> >> >> > for this project (COM objects in an ATL
> >> >> >> >> > service) I have no idea where I should implement
> >> >> >> >> > my synchronization routines.
> >> >> >> >> >
> >> >> >> >> > In particular, I can see these two points:
> >> >> >> >> >
> >> >> >> >> > 1) Do my need to maintain my own global list of pointers
> >> >> >> >> > pointing active COM clients, or is there a way
> >> >> >> >> > to retreive such a list?
> >> >> >> >> >
> >> >> >> >> > If I must maintain my own list of pointers, where
> >> >> >> >> > should I implement my code in the COM object class
> >> >> >> >> > to add/remove items to my global list?
> >> >> >> >> >
> >> >> >> >> > 2) I assume that when the independent thread fires an event,
> >> >> >> >> > I must use synchronization routines to be sure that
> >> >> >> >> > the COM client will remain usable until the return of
> >> >> >> >> > the fire_event function. If this is correct, where in the
> >> >> >> >> > COM object classshould I implement my synchronization
routines
> >> >> >> >> > for this purpose?
> >> >> >> >> >
> >> >> >> >> > 3) Is there other pitfalls I should be aware of?
> >> >> >> >> >
> >> >> >> >> > Thank you in advance for all help.
> >> >> >> >> >
> >> >> >> >> > Phil. Ten.
> >> >> >> >> >
> >> >> >> >> >
> >> >> >> >> >
> >> >> >> >>
> >> >> >> >>
> >> >> >> >
> >> >> >> >
> >> >> >>
> >> >> >>
> >> >> >
> >> >> >
> >> >>
> >> >>
> >> >
> >> >
> >>
> >>
> >
> >
>
>
- Next message: Bonj: "Initialization of default value and Persistance of ActiveX control"
- Previous message: land: "about IObjectContextInfo"
- In reply to: Alexander Nickolov: "Re: Independent thread fireing events in ATL Service synchronization requirements?"
- Next in thread: Alexander Nickolov: "Re: Independent thread fireing events in ATL Service synchronization requirements?"
- Reply: Alexander Nickolov: "Re: Independent thread fireing events in ATL Service synchronization requirements?"
- Messages sorted by: [ date ] [ thread ]
Relevant Pages
|