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


Авторские права

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

Здесь можно скачать бесплатно "Алекс Jenter - Программирование на Visual C++. Архив рассылки" в формате fb2, epub, txt, doc, pdf. Жанр: Программирование. Так же Вы можете читать книгу онлайн без регистрации и SMS на сайте LibFox.Ru (ЛибФокс) или прочесть описание и ознакомиться с отзывами.
Рейтинг:
Название:
Программирование на Visual C++. Архив рассылки
Автор:
Издательство:
неизвестно
Год:
неизвестен
ISBN:
нет данных
Скачать:

99Пожалуйста дождитесь своей очереди, идёт подготовка вашей ссылки для скачивания...

Скачивание начинается... Если скачивание не началось автоматически, пожалуйста нажмите на эту ссылку.

Вы автор?
Жалоба
Все книги на сайте размещаются его пользователями. Приносим свои глубочайшие извинения, если Ваша книга была опубликована без Вашего на то согласия.
Напишите нам, и мы в срочном порядке примем меры.

Как получить книгу?
Оплатили, но не знаете что делать дальше? Инструкция.

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

Описание и краткое содержание "Программирование на Visual C++. Архив рассылки" читать бесплатно онлайн.



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






 }

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

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

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

 pcs->RecursionCount = 1;

}


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

inline BOOL TryEnterCriticalSectionDbg(LPCRITICAL_SECTION pcs) {

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

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

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

  pcs->RecursionCount = 1;

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

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

  ::InterlockedIncrement(&pcs->LockCount);

  pcs->RecursionCount++;

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

 return TRUE;

}


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

inline VOID LeaveCriticalSectionDbg(LPCRITICAL_SECTION pcs) {

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

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

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

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

 if (--pcs->RecursionCount) {

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

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

  ::InterlockedDecrement(&pcs->LockCount);

 } else {

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

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

  ATLASSERT(NULL != pcs->OwningThread);

  pcs->OwningThread = 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 EnterCriticalSection EnterCriticalSectionDbg

#define TryEnterCriticalSection TryEnterCriticalSectionDbg

#define LeaveCriticalSection LeaveCriticalSectionDbg

#endif

Ну и заодно добавим еще один метод в наш класс CLock

Листинг 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-ном заходе,

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

   // стека для __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;

}


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


На Facebook В Твиттере В Instagram В Одноклассниках Мы Вконтакте
Подписывайтесь на наши страницы в социальных сетях.
Будьте в курсе последних книжных новинок, комментируйте, обсуждайте. Мы ждём Вас!

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

Книги похожие на "Программирование на Visual C++. Архив рассылки" читать онлайн или скачать бесплатно полные версии.


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

Все книги автора Алекс Jenter

Алекс Jenter - все книги автора в одном месте на сайте онлайн библиотеки LibFox.

Уважаемый посетитель, Вы зашли на сайт как незарегистрированный пользователь.
Мы рекомендуем Вам зарегистрироваться либо войти на сайт под своим именем.

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

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

А что Вы думаете о книге? Оставьте Ваш отзыв.