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

Тут можно читать онлайн Алекс Jenter - Программирование на Visual C++. Архив рассылки - бесплатно полную версию книги (целиком) без сокращений. Жанр: comp-programming. Здесь Вы можете читать полную версию (весь текст) онлайн без регистрации и SMS на сайте лучшей интернет библиотеки ЛибКинг или прочесть краткое содержание (суть), предисловие и аннотацию. Так же сможете купить и скачать торрент в электронном формате fb2, найти и слушать аудиокнигу на русском языке или узнать сколько частей в серии и всего страниц в публикации. Читателям доступно смотреть обложку, картинки, описание и отзывы (комментарии) о произведении.
  • Название:
    Программирование на Visual C++. Архив рассылки
  • Автор:
  • Жанр:
  • Издательство:
    неизвестно
  • Год:
    неизвестен
  • ISBN:
    нет данных
  • Рейтинг:
    4.33/5. Голосов: 91
  • Избранное:
    Добавить в избранное
  • Отзывы:
  • Ваша оценка:
    • 80
    • 1
    • 2
    • 3
    • 4
    • 5

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

Программирование на Visual C++. Архив рассылки - описание и краткое содержание, автор Алекс Jenter, читайте бесплатно онлайн на сайте электронной библиотеки LibKing.Ru

РАССЫЛКА ЯВЛЯЕТСЯ ЧАСТЬЮ ПРОЕКТА RSDN, НА САЙТЕ КОТОРОГО ВСЕГДА МОЖНО НАЙТИ ВСЮ НЕОБХОДИМУЮ РАЗРАБОТЧИКУ ИНФОРМАЦИЮ, СТАТЬИ, ФОРУМЫ, РЕСУРСЫ, ПОЛНЫЙ АРХИВ ПРЕДЫДУЩИХ ВЫПУСКОВ РАССЫЛКИ И МНОГОЕ ДРУГОЕ.

Программирование на Visual C++. Архив рассылки - читать онлайн бесплатно полную версию (весь текст целиком)

Программирование на Visual C++. Архив рассылки - читать книгу онлайн бесплатно, автор Алекс Jenter
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

static inline HANDLE _CriticalSectionGetEvent(LPCRITICAL_SECTION pcs) {

HANDLE ret = pcs->LockSemaphore;

if (!ret) {

HANDLE sem = ::CreateEvent(NULL, false, false, NULL);

ATLASSERT(sem);

if (!(ret = (HANDLE)::InterlockedCompareExchangePointer(

&pcs->LockSemaphore, sem, NULL))) ret = sem;

else ::CloseHandle(sem); // Кто-то успел раньше

}

return ret;

}

// Ждем, пока критическая секция не освободится либо время ожидания

// будет превышено

static inline VOID _WaitForCriticalSectionDbg(LPCRITICAL_SECTION_DBG pcs, int nLine, LPCSTR azFile) {

HANDLE sem = _CriticalSectionGetEvent(pcs);

DWORD dwWait;

do {

dwWait = ::WaitForSingleObject(sem, DEADLOCK_TIMEOUT);

if (WAIT_TIMEOUT == dwWait) {

ATLTRACE("Critical section timeout (%u msec):"

" tid 0x%04X owner tid 0x%04X\n"

"Owner lock from %hs line %u, waiter %hs line %u\n",

DEADLOCK_TIMEOUT, ::GetCurrentThreadId(), pcs->OwningThread,

pcs->m_azFile, pcs->m_nLine, azFile, nLine);

}

} while(WAIT_TIMEOUT == dwWait);

ATLASSERT(WAIT_OBJECT_0 == dwWait);

}

// Выставляем событие в активное состояние

static inline VOID _UnWaitCriticalSectionDbg(LPCRITICAL_SECTION pcs) {

HANDLE sem = _CriticalSectionGetEvent(pcs);

BOOL b = ::SetEvent(sem);

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

#define LeaveCriticalSection LeaveCriticalSectionDbg

#define CRITICAL_SECTION CRITICAL_SECTION_DBG

#define LPCRITICAL_SECTION LPCRITICAL_SECTION_DBG

#define PCRITICAL_SECTION PCRITICAL_SECTION_DBG

#endif

Приводим наши классы в соответствие

Листинг 17. Классы CLock и CScopeLock, вариант для отладки

class CLock {

friend class CScopeLock;

CRITICAL_SECTION m_CS;

public:

void Init() { ::InitializeCriticalSection(&m_CS); }

void Term() { ::DeleteCriticalSection(&m_CS); }

#if defined(CS_DEBUG)

BOOL Check() { return CheckCriticalSection(&m_CS); }

#endif

#if CS_DEBUG > 1

void Lock(int nLine, LPSTR azFile) {

EnterCriticalSectionDbg(&m_CS, nLine, azFile);

}

BOOL TryLock(int nLine, LPSTR azFile) {

return TryEnterCriticalSectionDbg(&m_CS, nLine, azFile);

}

#else

void Lock() {

::EnterCriticalSection(&m_CS);

}

BOOL TryLock() {

return ::TryEnterCriticalSection(&m_CS);

}

#endif

void Unlock() {

::LeaveCriticalSection(&m_CS);

}

};

class CScopeLock {

LPCRITICAL_SECTION m_pCS;

public:

#if CS_DEBUG > 1

CScopeLock(LPCRITICAL_SECTION pCS, int nLine, LPSTR azFile) : m_pCS(pCS) {

Lock(nLine, azFile);

}

CScopeLock(CLock& lock, int nLine, LPSTR azFile) : m_pCS(&lock.m_CS) {

Lock(nLine, azFile);

}

void Lock(int nLine, LPSTR azFile) {

EnterCriticalSectionDbg(m_pCS, nLine, azFile);

}

#else

CScopeLock(LPCRITICAL_SECTION pCS) : m_pCS(pCS) { Lock(); }

CScopeLock(CLock& lock) : m_pCS(&lock.m_CS) { Lock(); }

void Lock() { ::EnterCriticalSection(m_pCS); }

#endif

~CScopeLock() { Unlock(); }

void Unlock() { ::LeaveCriticalSection(m_pCS); }

};

#if CS_DEBUG > 1

#define Lock() Lock(__LINE__, __FILE__)

#define TryLock() TryLock(__LINE__, __FILE__)

#define lock(cs) lock(cs, __LINE__, __FILE__)

#endif

К сожалению, пришлось даже переопределить CScopeLock lock(cs), причем мы жестко привязались к имени переменной. Не говоря уж о том, что у нас наверняка получился конфликт имен, все-таки Lockдовольно популярное название для метода. Такой код не будет собираться, например, с популярнейшей библиотекой ATL. Тут есть два способа. Переименовать наши методы Lock() и TryLock() во что-нибудь более уникальное либо переименовать Lock() в ATL:

Читать дальше
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать


Алекс Jenter читать все книги автора по порядку

Алекс Jenter - все книги автора в одном месте читать по порядку полные версии на сайте онлайн библиотеки LibKing.




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


Отзывы читателей о книге Программирование на Visual C++. Архив рассылки, автор: Алекс Jenter. Читайте комментарии и мнения людей о произведении.


Понравилась книга? Поделитесь впечатлениями - оставьте Ваш отзыв или расскажите друзьям

Напишите свой комментарий
x