EnterCriticalSection() exception issue
-
Hi, I have a multithreaded program in which I use the following class object "ClassLock" the synchronize accesses :
#ifndef CLASSLOCK_H #define CLASSLOCK_H extern CRITICAL_SECTION g_ClassLock; class ClassLock { public: static void InitCriticalSection(); static void DelCriticalSection(); inline ClassLock() { EnterCriticalSection( &g_ClassLock ); } inline ~ClassLock() { LeaveCriticalSection( &g_ClassLock ); } }; #endif
I protect a function call by instantiating a ClassLock object at the beginning of the function :void MyFunc() { ClassLock l; ... }
But sometimes, don't know why, an exception is thrown. How can I deal with this ? My idea would be the following modification, but I don't know if it's safe and smart :inline ClassLock() { while(!TryEnterCriticalSection( &g_ClassLock )) { } }
Any other ideas ? Thanks -
Hi, I have a multithreaded program in which I use the following class object "ClassLock" the synchronize accesses :
#ifndef CLASSLOCK_H #define CLASSLOCK_H extern CRITICAL_SECTION g_ClassLock; class ClassLock { public: static void InitCriticalSection(); static void DelCriticalSection(); inline ClassLock() { EnterCriticalSection( &g_ClassLock ); } inline ~ClassLock() { LeaveCriticalSection( &g_ClassLock ); } }; #endif
I protect a function call by instantiating a ClassLock object at the beginning of the function :void MyFunc() { ClassLock l; ... }
But sometimes, don't know why, an exception is thrown. How can I deal with this ? My idea would be the following modification, but I don't know if it's safe and smart :inline ClassLock() { while(!TryEnterCriticalSection( &g_ClassLock )) { } }
Any other ideas ? Thanks -
Tnarol wrote:
How can I deal with this ?
Find out what the exception is. Is the purpose and use model of that class supposed to be evident? I don't get it.
led mike
led mike wrote:
Is the purpose and use model of that class supposed to be evident? I don't get it.
Yes, First at the beginning of your app you call InitCriticalSection() which is in fact InitializeCriticalSection() on a global g_ClassLock variable Then inside a function when you instantiate a ClassLock object it calls the constructor which locks the g_ClassLock variable using EnterCriticalSection( &g_ClassLock ) When the function return, the ClassLock object goes out of scope, so the destructor is called automatically and it does LeaveCriticalSection( &g_ClassLock ) Therefore the function has the g_ClassLock synchronization token for the duration of its' execution. Then at the end of the program DelCriticalSection must be called...and it does DeleteCriticalSection( &g_ClassLock ).
-
led mike wrote:
Is the purpose and use model of that class supposed to be evident? I don't get it.
Yes, First at the beginning of your app you call InitCriticalSection() which is in fact InitializeCriticalSection() on a global g_ClassLock variable Then inside a function when you instantiate a ClassLock object it calls the constructor which locks the g_ClassLock variable using EnterCriticalSection( &g_ClassLock ) When the function return, the ClassLock object goes out of scope, so the destructor is called automatically and it does LeaveCriticalSection( &g_ClassLock ) Therefore the function has the g_ClassLock synchronization token for the duration of its' execution. Then at the end of the program DelCriticalSection must be called...and it does DeleteCriticalSection( &g_ClassLock ).
-
Tnarol wrote:
on a global g_ClassLock variable
I don't understand what problem a "global" critical section solves, you want to synchronize everything in the process? :confused:
led mike
It's just that a global variable is a simple kind of synchronization resource that can be seen and shared by several threads in a program. I could have this variable static in the class, but there are some strange things happening with static variables members of a class, if you use them very early in the program they are sometimes not yet created and it makes you crash. I don't have a logical explanation for this but that's my experience.
-
It's just that a global variable is a simple kind of synchronization resource that can be seen and shared by several threads in a program. I could have this variable static in the class, but there are some strange things happening with static variables members of a class, if you use them very early in the program they are sometimes not yet created and it makes you crash. I don't have a logical explanation for this but that's my experience.
Tnarol wrote:
It's just that a global variable is a simple kind of synchronization resource that can be seen and shared by several threads in a program.
I'm sorry but that does not explain anything. A Critical Section is used to synchronize access to data or a section of code, this implies "context" associated with the CS. Have one as "global" elimintates all context.
Tnarol wrote:
they are sometimes not yet created
"Created"? static variable addresses are known at load time, therefore any code that uses them has a good address. Anyway, global or static, I still don't see how that solves anything in regards to using a CS.
led mike
-
Hi, I have a multithreaded program in which I use the following class object "ClassLock" the synchronize accesses :
#ifndef CLASSLOCK_H #define CLASSLOCK_H extern CRITICAL_SECTION g_ClassLock; class ClassLock { public: static void InitCriticalSection(); static void DelCriticalSection(); inline ClassLock() { EnterCriticalSection( &g_ClassLock ); } inline ~ClassLock() { LeaveCriticalSection( &g_ClassLock ); } }; #endif
I protect a function call by instantiating a ClassLock object at the beginning of the function :void MyFunc() { ClassLock l; ... }
But sometimes, don't know why, an exception is thrown. How can I deal with this ? My idea would be the following modification, but I don't know if it's safe and smart :inline ClassLock() { while(!TryEnterCriticalSection( &g_ClassLock )) { } }
Any other ideas ? Thanksvoid MyFunc() { ClassLock l; ... }
You're probably getting an exception because you are entering a critical section that hasn't been initialized yet. You also don't want to create a new critical section every time you enter the function otherwise it will never block. Try this:class CMyCriticalSection
{
private:
CRITICAL_SECTION CritSec;
protected:
public:
CMyCriticalSection() {::InitializeCriticalSection(&CritSec);}
virtual ~CMyCriticalSection() {::DeleteCriticalSection(&CritSec);}void Enter() {::EnterCriticalSection(&CritSec);} void Leave() {::LeaveCriticalSection(&CritSec);}
};
CMyCriticalSection MyFuncCritSec;
void MyFunc()
{
MyFuncCritSec.Enter();... (do thread protected stuff) MyFuncCritSec.Leave();
}
-
void MyFunc() { ClassLock l; ... }
You're probably getting an exception because you are entering a critical section that hasn't been initialized yet. You also don't want to create a new critical section every time you enter the function otherwise it will never block. Try this:class CMyCriticalSection
{
private:
CRITICAL_SECTION CritSec;
protected:
public:
CMyCriticalSection() {::InitializeCriticalSection(&CritSec);}
virtual ~CMyCriticalSection() {::DeleteCriticalSection(&CritSec);}void Enter() {::EnterCriticalSection(&CritSec);} void Leave() {::LeaveCriticalSection(&CritSec);}
};
CMyCriticalSection MyFuncCritSec;
void MyFunc()
{
MyFuncCritSec.Enter();... (do thread protected stuff) MyFuncCritSec.Leave();
}
Thanks, it works fine so far...but the exception occurs very rarely so time will tell. The problem with this kind of class is that you have to leave critical section explicitly so if you have functions with many return points you must copy the "Leave()" everywhere. Anyway I'm quite confident in this implementation.
-
Thanks, it works fine so far...but the exception occurs very rarely so time will tell. The problem with this kind of class is that you have to leave critical section explicitly so if you have functions with many return points you must copy the "Leave()" everywhere. Anyway I'm quite confident in this implementation.
>>The problem with this kind of class is that you have to leave critical section explicitly so if >>you have functions with many return points you must copy the "Leave()" everywhere. Cool. I guess I prefer it that way personally :) I can't recall ever needing to block an entire function. Anyway I suspect the exception is unrelated to the critical section. But if it only rarely happens I guess it's ok? Best of luck, Mark
-
Hi, I have a multithreaded program in which I use the following class object "ClassLock" the synchronize accesses :
#ifndef CLASSLOCK_H #define CLASSLOCK_H extern CRITICAL_SECTION g_ClassLock; class ClassLock { public: static void InitCriticalSection(); static void DelCriticalSection(); inline ClassLock() { EnterCriticalSection( &g_ClassLock ); } inline ~ClassLock() { LeaveCriticalSection( &g_ClassLock ); } }; #endif
I protect a function call by instantiating a ClassLock object at the beginning of the function :void MyFunc() { ClassLock l; ... }
But sometimes, don't know why, an exception is thrown. How can I deal with this ? My idea would be the following modification, but I don't know if it's safe and smart :inline ClassLock() { while(!TryEnterCriticalSection( &g_ClassLock )) { } }
Any other ideas ? ThanksYou need two SEPARATE objects. The first object constructor initializes the critical section, and its destructor deletes the critical section. It has a member function Lock() and Unlock() The second class, its constructor Enters the critical section of first object, by calling its Lock function. The destructor of this class calls the Unlock() of the first class. That way, you don't have to worry about calling Unlock() explicitly from your code. You also don't have to use a 'global' class from your common code, you use instances of the second class. If you don't want to block out the entire scope of a function, then use the local scoping operators around the second class and the code like so { SecondClass MyLocker; ... code } and it will release when closing brace is met. This is also handy when there is an exception, your critical section is not permanently locked and lost by the unwinding of the exception.
Any sufficiently gross incompetence is nearly indistinguishable from malice.