简体   繁体   中英

Is there any way that Enter/LeaveCriticalSection could leave a handle behind

I have the following code in my program:

  EnterCriticalSection(&critsec[x]);
  // stuff
  LeaveCriticalSection(&critsec[x]);

It works fine 99.999% of the time but occasionally a handle seems to get left behind. Now I have done the obvious things like make sure that x did not change value between the enter and make sure that there isn't any "return" or "break" inside "// stuff" but I was wondering if there could be something else that would cause an enter/leave pair to leave a handle behind. Perhaps running out of memory or overflowing some counter in the OS or whatever.

EDIT: I am new to C++, the program has only recently been converted from C. It has no exceptions anywhere in the entire program.

If you don't explicitly delete the critical section and if there was ever contention on the critical section, you will leak a handle. Some implementations of critical sections on Windows allocate a semaphore when two or more threads overlap in their attempts to enter a single critical section.

It's not a leak. Or rather, it isn't a leak if the number of "leaked" handles is less than or equal to the number of global critical sections you are using.

Mick,

There are a number of things that could be happening.

Exceptions can cause control flow to exit the block before executing the LeaveCriticalSection call. To avoid this problem you can wrap up the entering & exiting of the critical section within a stack based object using the Resource Acquisition Is Initialisation (RAII) pattern.

Without a more complete listing, however, it is impossible to say whether there are any other issues with your code.

Cheers Seb

Since you're in C++ land, an exception leaving that // stuff part will skip LeaveCriticalSection() . Look up RAII ("Resource-Aquisition-Is-Initialization") as a tool to prevent that from happening. Here's a somewhat simple example for such a class:

class CriticalSectionLock {
public:
  CriticalSectionLock(CRITICAL_SECTION& c) : cs_(c){EnterCriticalSection(&cs_);}
  ~CriticalSectionLock()                           {LeaveCriticalSection(&cs_);}
private:
  CRITICAL_SECTION& cs_;
};


void f()
{
  CriticalSectionLock lock(critsec[x])
   // stuff
} // lock's destructor will automagically call LeaveCriticalSection()

On a side-note: Deadlocks can sometimes give the impression of some lock not being properly unlocked.

The most probable cause is an exception. Are you catching the exceptions inside this function and whether they call Leave or not? Also, note that it is better to use CSingleLock class to lock the critical section instead of using raw APIs like this. By using CSingleLock you can guantee proper cleanup incase of exceptions.

Expanding on sbi's answer (as you say you're new to C++), an exception ignores the rest of the code from the place where it is invoked until it reaches a place where the exception can be handled (a 'catch') - the only exception to this is when the exception wraps up memory in a stack - it calls the destructors of stack variables.

To ensure that the 'Leave' is always called, use the following class: (excuse the lack of formatting), and put both an instance of this class and the critical code in a new stack. This ensures that the 'Leave' is always called, both in non-exception and exception scenarios.

edit: Updating poc code to reflect comment.

class AutoCritical
{
public:
  AutoCritical(CritSec * p_CritSec) : m_Sec(p_CritSec) 
   { EnterCriticalSection(m_CritSec); };
  ~AutoCritical() { LeaveCriticalSection(m_CritSec); };
private:
  CritSec * m_Sec;
}; 

calling place:

// non-critical code ....
{   //open stack for critical code
    AutoCritical a(&critsec[x]);
    // do critical stuff here ...
}   // close stack

您是否有可能因输入/离开不匹配而丢失了句柄,而是忘记了调用DeleteCriticalSection。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM