Managed C++ Safe CritcalSection

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

In the prior C++ world we used to have locks that we would declare on the
stack such that as the stack was unwound the critical section would be
released. I am wondering how this works with managed C++. Here is a class
that I wrote to wrap a monitor for an object around. I would appreciate any
comments about this I have looked at it in the debugger and it appears to
work. This isn't a class that you would use gcnew on, but declare on the
stack: ESLock myLock(mySharedObject);

using namespace System;
using namespace System::Threading;
public ref class ESLock : IDisposable
{
public:
ESLock(Object ^ obj) : m_bLocked(false), m_obj(obj)
{
Monitor::Enter(obj);
m_bLocked = true;
}

~ESLock()
{
if(m_bLocked) Unlock();
}

void Unlock()
{
if(!m_bLocked) return;

Monitor::Exit(m_obj);
m_bLocked = false;
}

protected:
Object ^m_obj;
bool m_bLocked;
};
 
Just for your information, managed code destructors are not similar to
C++ destructors in spite of the identical syntax. A managed destructor
is not guaranteed to be called at some defined time after the object
goes out-of-scope. You should always call Monitor::Exit in finally
block instead of relying on destructors. As the result, your class is
not very helpful unless it is comsumed by some language like C# which
supports IDisposeable interface with "using" keyword (however, C#
already has the "lock" keyword for this case).
 
I understand what you are saying and I am looking at this as an academic
exercise in understanding the differences between the various ways to create
a class and instantiate it.

But there is a difference here:

ERLock foo(m_SharedObject);

and

ERLock^ foo = gcnew ERLock(m_SharedObject);

I am also interested in what the IDisposable interface is doing for you.

From the debugger there is a difference when you declare something on the
managed heap using gcnew and you declare it on the stack.

I also understand the the IDisposable interface is connected to the
destructor in Managed C++ VS2005.

It appears to me that something is different here. I am providing a class
that I was using to test. It appears to me that the destructor is firing
deterministically when you declare something on the stack. I just want to
make sure that I am clear what is going on.

I am looking to understand both destructors related to declaring something
on the stack or managed heap. And also understand what adding the
IDisposable interface to a C++ class does.

Regards

Frank
 
In .NET, class instances are allocated on the managed heap and struct
(value-type) instances are allocated on the stack. I did not know that
managed C++ compiler allows allocation of object on the stack in form
of ERLock foo(m_SharedObject);. If it is so, your sollution would work.
 
Frank Postle wrote:

Just a comment on the title of the post. 'Safe CriticalSection'. While I
agree that multithreaded applications have issues that need to be
solved, it is vitally important to realise that locking a section of
code should be treated as a last resort. When you use a critical section
you are by definition blocking a thread, and a blocked thread is a
thread that does not do any work. So your first thought should never be
to make code single threaded. By all means do it if there is no other
solution, but you should investigate the possibilities of designing away
the multithreaded issues first.

As an example, I would point you to ATL Server in the unmanaged world.
Microsoft created this to be a high performance library for web
applications and services (which it still is), and the first thing they
did was design it so that they did not need *any* critical sections.

Richard
 
Back
Top