Чтение онлайн

ЖАНРЫ

Программирование на Visual C++. Архив рассылки

Jenter Алекс

Шрифт:

 ATLASSERT(b);

}

// Инициализируем критическую секцию.

inline VOID InitializeCriticalSectionDbg(LPCRITICAL_SECTION_DBG pcs) {

 // Пусть система заполнит свои поля

 InitializeCriticalSection(pcs);

 // Заполняем наши поля

 pcs->m_nLine = 0;

 pcs->m_azFile = NULL;

}

//
Освобождаем ресурсы, занимаемые критической секцией

inline VOID DeleteCriticalSectionDbg(LPCRITICAL_SECTION_DBG pcs) {

 // Проверяем, чтобы не было удалений "захваченных" критических секций

 ATLASSERT(0 == pcs->m_nLine && NULL == pcs->m_azFile);

 // Остальное доделает система

 DeleteCriticalSection(pcs);

}

// Заполучем критическую секцию в свое пользование

inline VOID EnterCriticalSectionDbg(LPCRITICAL_SECTION_DBG pcs, int nLine, LPSTR azFile) {

 if (::InterlockedIncrement(&pcs->LockCount)) {

// LockCount стал больше нуля.

// Проверяем идентификатор нити

if (pcs->OwningThread == (HANDLE)::GetCurrentThreadId) {

// Нить та же самая. Критическая секция наша.

// Никаких дополнительных действий не производим.

// Это не совсем верно, так как возможно, что непарный

// вызов ::LeaveCriticalSection был на n-ном заходе,

// и это прийдется отлавливать вручную, но реализация

// стека для __LINE__ и __FILE__ сделает нашу систему

// более громоздкой. Если это действительно необходимо,

// Вы всегда можете сделать это самостоятельно

pcs->RecursionCount++;

return;

}

// Критическая секция занята другой нитью.

// Придется подождать

_WaitForCriticalSectionDbg(pcs, nLine, azFile);

 }

 // Либо критическая секция была "свободна",

 // либо мы дождались. Сохраняем идентификатор текущей нити.

 pcs->OwningThread = (HANDLE)::GetCurrentThreadId;

 pcs->RecursionCount = 1;

 pcs->m_nLine = nLine;

 pcs->m_azFile = azFile;

}

// Заполучаем критическую секцию если она никем не занята

inline BOOL TryEnterCriticalSectionDbg(LPCRITICAL_SECTION_DBG pcs, int nLine, LPSTR azFile) {

 if (-1L == ::InterlockedCompareExchange(&pcs->LockCount, 0, -1)) {

// Это первое обращение к критической секции

pcs->OwningThread = (HANDLE)::GetCurrentThreadId;

pcs->RecursionCount = 1;

pcs->m_nLine = nLine;

pcs->m_azFile = azFile;

 } else if (pcs->OwningThread == (HANDLE)::GetCurrentThreadId) {

//
Это не первое обращение, но из той же нити

::InterlockedIncrement(&pcs->LockCount);

pcs->RecursionCount++;

 } else return FALSE; // Критическая секция занята другой нитью

 return TRUE;

}

// Освобождаем критическую секцию

inline VOID LeaveCriticalSectionDbg(LPCRITICAL_SECTION_DBG pcs) {

 // Проверяем, чтобы идентификатор текущей нити совпадал

 // с идентификатором нити-влядельца.

 // Если это не так, скорее всего мы имеем дело с ошибкой

 ATLASSERT(pcs->OwningThread == (HANDLE)::GetCurrentThreadId);

 if (--pcs->RecursionCount) {

// Не последний вызов из этой нити.

// Уменьшаем значение поля LockCount

::InterlockedDecrement(&pcs->LockCount);

 } else {

// Последний вызов. Нужно "разбудить" какую-либо

// из ожидающих ниток, если таковые имеются

ATLASSERT(NULL != pcs->OwningThread);

pcs->OwningThread = NULL;

pcs->m_nLine = 0;

pcs->m_azFile = NULL;

if (::InterlockedDecrement(&pcs->LockCount) >= 0) {

// Имеется, как минимум, одна ожидающая нить

_UnWaitCriticalSectionDbg(pcs);

}

 }

}

// Удостоверяемся, что ::EnterCriticalSection была вызвана

// до вызова этого метода

inline BOOL CheckCriticalSection(LPCRITICAL_SECTION pcs) {

 return pcs->LockCount >= 0

&& pcs->OwningThread == (HANDLE)::GetCurrentThreadId;

}

// Переопределяем все функции для работы с критическими секциями.

// Определение класса CLock должно быть после этих строк

#define InitializeCriticalSection InitializeCriticalSectionDbg

#define InitializeCriticalSectionAndSpinCount(pcs, c) \

 InitializeCriticalSectionDbg(pcs)

#define DeleteCriticalSection DeleteCriticalSectionDbg

#define EnterCriticalSection(pcs) EnterCriticalSectionDbg(pcs, __LINE__, __FILE__)

#define TryEnterCriticalSection(pcs) TryEnterCriticalSectionDbg(pcs, __LINE__, __FILE__)

Поделиться с друзьями: