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

Здесь есть возможность читать онлайн «Алекс Jenter - Программирование на Visual C++. Архив рассылки» весь текст электронной книги совершенно бесплатно (целиком полную версию без сокращений). В некоторых случаях можно слушать аудио, скачать через торрент в формате fb2 и присутствует краткое содержание. Жанр: Программирование, на русском языке. Описание произведения, (предисловие) а так же отзывы посетителей доступны на портале библиотеки ЛибКат.

Программирование на Visual C++. Архив рассылки: краткое содержание, описание и аннотация

Предлагаем к чтению аннотацию, описание, краткое содержание или предисловие (зависит от того, что написал сам автор книги «Программирование на Visual C++. Архив рассылки»). Если вы не нашли необходимую информацию о книге — напишите в комментариях, мы постараемся отыскать её.

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

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

Ниже представлен текст книги, разбитый по страницам. Система сохранения места последней прочитанной страницы, позволяет с удобством читать онлайн бесплатно книгу «Программирование на Visual C++. Архив рассылки», без необходимости каждый раз заново искать на чём Вы остановились. Поставьте закладку, и сможете в любой момент перейти на страницу, на которой закончили чтение.

Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

Листинг 15. Класс CLock с новым методом

class CLock {

friend class CScopeLock;

CRITICAL_SECTION m_CS;

public:

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

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

void Lock() { ::EnterCriticalSection(&m_CS); }

BOOL TryLock() { return ::TryEnterCriticalSection(&m_CS); }

void Unlock() { ::LeaveCriticalSection(&m_CS); }

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

};

Использовать метод Check() в release-конфигурациях не стоит, возможно, что в будущем, в какой-нибудь Windows64, структура RTL_CRITICAL_SECTION изменится и результат такой проверки не определен. Так что ему самое место "жить" внутри всяческих ASSERT'ов.

Итак, что мы имеем? Мы имеем проверку на лишний вызов ::LeaveCriticalSection() и ту же трассировку для блокировок. Не так уж много. Особенно, если трассировка о блокировке имеет место, а вот нить, забывшая освободить критическую секцию, давно завершилась. Как быть? Вернее, что бы еще придумать, чтобы ошибку проще было выявить? Как минимум, прикрутить сюда __LINE__ и __FILE__, константы, соответствующие текущей строке и имени файла на момент компиляции этого метода.

VOID EnterCriticalSectionDbg(LPCRITICAL_SECTION pcs, int nLine = __LINE__, azFile = __FILE__);

Компилируем, запускаем… Результат удивительный. Хотя правильный. Компилятор честно подставил номер строки и имя файла, соответствующие началу нашей EnterCriticalSectionDbg(). Так что придется попотеть немного больше. __LINE__ и __FILE__ нужно вставить в #define'ы, тогда мы получим действительные номер строки и имя исходного файла. Теперь вопрос, куда же сохранить эти параметры для дальнейшего использования? Причем хочется оставить за собой возможность вызова стандартных функций API наряду с нашими собственными? На помощь приходит C++: просто создадим свою структуру, унаследовав ее от RTL_CRITICAL_SECTION. Итак:

Листинг 16. Реализация критических секций с сохранением строки и имени файла

#if defined(_DEBUG) && !defined(_NO_DEADLOCK_TRACE)

#define DEADLOCK_TIMEOUT 30000

#define CS_DEBUG 2

// Наша структура взамен CRITICAL_SECTION

struct CRITICAL_SECTION_DBG : public CRITICAL_SECTION {

// Добавочные поля

int m_nLine;

LPCSTR m_azFile;

};

typedef struct CRITICAL_SECTION_DBG *LPCRITICAL_SECTION_DBG;

// Создаем на лету событие для операций ожидания,

// но никогда его не освобождаем. Так удобней для отладки

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-ном заходе,

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

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

Интервал:

Закладка:

Сделать

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

Представляем Вашему вниманию похожие книги на «Программирование на Visual C++. Архив рассылки» списком для выбора. Мы отобрали схожую по названию и смыслу литературу в надежде предоставить читателям больше вариантов отыскать новые, интересные, ещё непрочитанные произведения.


Алексей Макеев - Смертельный архив
Алексей Макеев
libcat.ru: книга без обложки
Алексей Апухтин
Отзывы о книге «Программирование на Visual C++. Архив рассылки»

Обсуждение, отзывы о книге «Программирование на Visual C++. Архив рассылки» и просто собственные мнения читателей. Оставьте ваши комментарии, напишите, что Вы думаете о произведении, его смысле или главных героях. Укажите что конкретно понравилось, а что нет, и почему Вы так считаете.

x