Introduction
Working with critical section is not quite an easy task. Of course, if you have just two threads and one critical section, it's alright. But if you have about 10 threads, and you have to synchronize the use of about 20-30 variables then you will probably have problems. A very useful tool used is ProcessExplorer from Sysinternals. But it doesn't tell you a lot about the Critical Section object. So, I needed a way to trace all the critical sections, when they get locked/unlocked, and by whom. That is all about it.
Using the code
To use these classes, you got to have the basics about CCriticalSection
and CSingleLock
. If you don't, come back when you read all about it from MSDN. This works both for /DEBUG mode and /RELEASE mode. But only in /DEBUG mode you'll be able to trace all the Critical Section "activity". In /RELEASE mode you will not get any debug messages. Still, if you wish to see them, then edit debugtrace.cpp and debugtrace.h files and remove all the #ifndef
and #endif
lines.
First add debugtrace.h, debugtrace.cpp, spinlock.h, spinlock.cpp, namedcriticalsection.h and namedcriticalsection.cpp files to your project and of course #include "namedcriticalsection.h"
where needed.
To use CNamedCriticalSection
, it's very easy, just follow the following steps:
#include "namedcriticalsection.h"
class MyClass
{
CNamedCriticalSection Section;
public:
MyClass();
~MyClass();
void SomeMethod(void);
...
};
#include "myclass.h"
MyClass::MyClass()
: Section( "MyClass" )
{
...
}
MyClass::~MyClass()
{
...
}
void MyClass::SomeMethod(void)
{
CSpinLock Spin( &Section, "MyClass::SomeMethod" );
if( Spin.Lock() )
{
...
Spin.Unlock();
}
}
OK. So, the class has a member function which locks the section and gets exclusive rights to operate with some data. We also assumed that the MyClass::SomeFunction()
gets executed only by one single thread, let's say the main thread of the process.
Let's say that the application starts another thread which wants to use the same data as the one MyClass::SomeFunction()
locks. This means that we have to wait for the critical section to get unlocked. Once it gets unlocked by the main thread, this new thread locks it. Please, also read the comments in the code sample below:
UINT SomeThread( LPVOID lParam )
{
MyClass *pmy = NULL;
if( NULL == ( pmy = (MyClass*)lParam ) )
return 0;
CSpinLock Spin( &(pmy->Section), "SomeThread" );
if( Spin.Lock() )
{
...
Spin.Unlock();
}
...
return 1;
}
That's all! It's very simple (I think:)), but I am sure you'll find it useful. It made me find a lot of bugs.
One more thing: If your application already has a lot of source-code you might think that it is really hard to replace CCriticalSection
with CNamedCriticalSection
and CSingleLock
with CSpinLocK
. Well, it is not hard, it's quite simple actually. Just remember that CNamedCriticalSection
and CSpinLock
constructors need a name string.
Points of Interest
It's interesting:). Seriously, you will need this while coding large applications with a lot of threads.
History
- Version 1.0 - 23rd- February-2005 - As promised in the CDebugTrace article, I have posted this one, too.