Re: Lock/Unlock of ATL object from client
"dirk" <dirk.kapusta@reply_in_newsgroup> schrieb im Newsbeitrag
news:O10jn6OhGHA.4080@TK2MSFTNGP03.phx.gbl...
Basically there can be 2 or more clients in different threads which
share a
single object (the one that should be locked). These clients must be
able to
change some state of the shared object and then call multiple methods.
The
object's state must not be changed during these calls by another client
in
a different thread.
I had already thought about a locking method that is associated with the
client
thread rather than the internal thread. Jeffrey Richter describes a
critical section
replacement called Optex in his book "Programming Applications for
Microsoft Windows". I think I could modify this version to use an
explicit
thread id instead of GetCurrentThreadId. The client would then pass its
own
thread id when calling Lock/Unlock.
If your clients always call your Lock and Unlock methods before and after
calling the critical methods, a single event object should be enough. When
an instance of your object is created it creates an event object:
HRESULT FinalConstruct
{
m_hEvent = CreateEvent(0, FALSE, TRUE, 0);
return S_OK;
}
Your Lock method waits for this event to be raised
HRESULT YourObject::Lock()
{
WaitForSingleObject(m_hEvent, INFINITE);
return S_OK;
}
And your Unlock method triggers the event
HRESULT YourObject::Unlock()
{
SetEvent(m_hEvent);
return S_OK;
}
You could additionally separate the critical functions from the main object
and let clients access them through a separate helper object. Instead of
locking your object, the client requests an interface, which gives him
access to the critical functions. Of cause, your object returns such an
object only if no other helper object exists. The helper object can delegate
all calls to the main object, and when a helper object is finally released,
it tells the main object that it is safe to create another helper object for
another client.
HRESULT YourObject::GetHelper(IHelper** pVal)
{
if (m_HelperExists) return E_FAIL;
// instead of railing, you could also wait until the other
client
// doesn't use the helper any longer.
m_HelperExists = true;
CComObject<Helper>* helper;
CComObject<Helper>::CreateInstance(&helper);
helper->SetMainObject(this);
*pVal = helper;
(*pVal)->AddRef();
return S_OK;
}
void Helper::FinalRelease()
{
m_Owner->HelperIsGoneNow();
}
That would force all clients to lock the object before calling critical
methods and smart pointers will help them not only to release the helper
object, but also to unlock your object.
HTH
Heinz