Программирование на Visual C++. Архив рассылки
Шрифт:
Листинг 6. Код классов CLock, CAutoLock и CScopeLock
Классы CLock
Листинг 7. Пример использования CScopeLock
Весьма интересное и увлекательное занятие. Можно потратить часы и недели, но так и не найти, где именно возникает проблема. Стоит уделить этому особо пристальное внимание. Ошибки, связанные с критическими секциями бывают двух типов: ошибки реализации и архитектурные ошибки.
Это довольно легко обнаруживаемые ошибки, как правило, связанные с непарностью вызовов ::EnterCriticalSection и ::LeaveCriticalSection.
Листинг 8. Пропущен вызов ::EnterCriticalSection
::LeaveCriticalSection
Листинг 9. Пропущен вызов ::LeaveCriticalSection
В этом примере, конечно, имеет смысл воспользоваться классом типа CScopeLock.
Кроме того, случается, что ::EnterCriticalSection вызывается без инициализации критической секции с помощью ::InitializeCriticalSection. Особенно часто такое случается с проектами, написанными с помощью ATL. Причем в debug-версии все работает замечательно, а release-версия рушится. Это происходит из-за так называемой "минимальной" CRT (_ATL_MIN_CRT), которая не вызывает конструкторы статических объектов (Q166480, Q165076). В ATL версии 7.0 эту проблему решили.
Еще я встречал такую ошибку: программист пользовался классом типа CScopeLock, но для экономии места называл эту переменную одной буквой:
и как-то раз просто пропустил имя у переменной. Получилось
а что это означает? Компилятор честно сделал вызов конструктора CScopeLock, и тут же уничтожил этот безымянный объект, как и положено по стандарту. Т.е. сразу же после вызова метода Lock последовал вызов Unlock, и синхронизация перестала иметь место. Вообще, давать переменным, даже локальным, имена из одной буквы – путь быстрого наступления на всяческие грабли.
СОВЕТ
Если у Вас в процедуре больше одного цикла, то вместо int i, j, k стоит все-таки использовать что-то вроде int nObject, nSection, nRow.
Самая известная из них это блокировка (deadlock) когда две нити пытаются захватить две или более критических секций, причем делают это в разном порядке.
Листинг 10. Взаимоблокировка двух ниток