Есть ли способ, чтобы Enter / LeaveCriticalSection мог оставить дескриптор позади - PullRequest
0 голосов
/ 19 ноября 2009

В моей программе есть следующий код:

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

Хорошо работает в 99,999% случаев, но иногда кажется, что ручка осталась позади. Теперь я сделал очевидные вещи, такие как убедиться, что x не изменил значение между вводом, и убедиться, что нет никаких «return» или «break» внутри «// stuff», но мне было интересно, может ли быть что-то иначе это может привести к тому, что пара входа / выхода оставит дескриптор позади. Возможно, недостаточно памяти или переполнен какой-то счетчик в ОС или что-то в этом роде.

РЕДАКТИРОВАТЬ: Я новичок в C ++, программа была недавно преобразована из C. Она не имеет исключений во всей программе.

Ответы [ 6 ]

3 голосов
/ 19 ноября 2009

Если вы не удалите критическую секцию явным образом и если в критической секции когда-либо возникали конфликты, вы потеряете дескриптор. Некоторые реализации критических разделов в Windows выделяют семафор, когда два или более потоков перекрываются при попытке войти в один критический раздел.

Это не утечка. Точнее, это не утечка, если количество «утечек» дескрипторов меньше или равно числу используемых вами критических глобальных секций.

2 голосов
/ 19 ноября 2009

Мик,

Существует множество вещей, которые могут происходить.

Исключения могут привести к тому, что поток управления выйдет из блока перед выполнением вызова LeaveCriticalSection. Чтобы избежать этой проблемы, вы можете обернуть вход и выход критической секции внутри стекового объекта, используя шаблон Resource Acquisition Is Initialisation (RAII).

Однако без более полного списка невозможно сказать, есть ли какие-либо другие проблемы с вашим кодом.

Приветствие Себ

1 голос
/ 19 ноября 2009

Расширяя ответ sbi (как вы говорите, вы новичок в C ++), исключение игнорирует остальную часть кода с того места, где он вызывается, пока не достигнет места, где может быть обработано исключение («зацепка»). ) - единственное исключение - когда исключение оборачивает память в стеке - оно вызывает деструкторы переменных стека.

Чтобы гарантировать, что всегда вызывается 'Leave', используйте следующий класс: (извините за отсутствие форматирования) и поместите экземпляр этого класса и критический код в новый стек. Это гарантирует, что 'Leave' всегда вызывается, как в сценариях не исключений, так и исключений.

edit: Обновление кода p-o-c для отражения комментария.

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

место вызова:

// non-critical code ....
{   //open stack for critical code
    AutoCritical a(&critsec[x]);
    // do critical stuff here ...
}   // close stack
1 голос
/ 19 ноября 2009

Наиболее вероятная причина - исключение. Вы ловите исключения внутри этой функции и вызывают ли они Leave или нет? Также обратите внимание, что лучше использовать класс CSingleLock для блокировки критической секции, а не использовать необработанные API, как это. Используя CSingleLock, вы можете гарантировать правильную очистку в случае исключений.

1 голос
/ 19 ноября 2009

Поскольку вы находитесь на земле C ++, исключение, при котором эта часть // stuff будет пропущено LeaveCriticalSection(). Посмотрите на RAII («Resource-Aquisition-Is-Initialization») как на инструмент для предотвращения этого. Вот несколько простой пример для такого класса:

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()

На заметку: иногда из-за блокировок может сложиться впечатление, что какой-то замок не разблокирован должным образом.

0 голосов
/ 19 ноября 2009

Возможно ли, что вы не теряете дескриптор с несоответствующим Enter / Leave, а скорее забываете вызывать DeleteCriticalSection.

...