- •1.Объекты ядра
- •2. Учет пользователей объектов ядра
- •3. Защита объектов ядра
- •4. Таблица описателей объектов ядра
- •5. Создание объекта ядра
- •6. Закрытие объекта ядра
- •7. Совместное использование объектов ядра несколькими процессами
- •8. Наследование описателя объекта
- •9. Изменение флагов описателя
- •10. Именованные объекты
- •11. Дублирование описателей объектов
- •12. Синхронизация с потоков с помощью объектов ядра
- •13. Wait-функции
- •13.1. Побочные эффекты успешного ожидания
- •14. События
- •15. Семафоры
- •16. Мьютексы
- •17. Отказ от объекта-мьютекса
- •18. Мьютексы и критические секции
- •19. Сводная таблица объектов, используемых для синхронизации потоков
- •20. Порядок выполнения работы
- •21. Контрольные вопросы
17. Отказ от объекта-мьютекса
Объект-мьютекс отличается от остальных объектов ядра тем, что занявшему его потоку передаются права на владение им. Прочие объекты могут быть либо свободны, либо заняты — вот, собственно, и все. А объекты-мьютексы способны еще и запоминать, какому потоку они принадлежат. Если какой-то посторонний поток попытается освободить мьютекс вызовом функции ReleaseMutex, то она, проверив идентификаторы потоков и обнаружив их несовпадение, ничего делать не станет, а просто вернет FALSE. Тут же вызвав GetLastError, получим значение ERROR_NOT_OWNER.
Если поток, которому принадлежит мьютекс, завершится, не успев его освободить, система считает, что произошел отказ от мьютекса, и автоматически переводит его в свободное состояние (сбрасывая при этом все его счетчики в исходное состояние). Если этот мьютекс ждут другие потоки, система, как обычно, «по-честному» выбирает один из потоков и позволяет ему захватить мьютекс. Тогда Wait-функция возвращает потоку WAIT_ABANDO NED вместо WAIT_OBJECT_0, и тот узнает, что мьютекс освобожден некорректно. Данная ситуация, конечно, не самая лучшая. Выяснить, что сделал с защищенными данными завершенный поток — бывший владелец объекта-мьютекса, увы невозможно. В реальности программы никогда специально не проверяют возвращаемое значение на WAIT_ABANDONED, потому что такое завершение потоков происходит очень редко. (Вот, кстати, еще один яркий пример, доказывающий, что не надо пользоваться функцией TerminateThread.)
18. Мьютексы и критические секции
Мьютексы и критические секции одинаковы в том, как они влияют на планирование ждущих потоков, но различны по некоторым другим характеристикам. Эти объекты сравниваются в следующей таблице.
Характеристики |
Объект-мьютекс |
Обьект — критическая секция |
Быстродействие |
Малое |
Высокое |
Возможность использования за границами процесса |
Да |
Нет |
Объявление |
HANDLE hmfx; |
CRITICAL_SECTION cs; |
Инициализация |
hmtx = CreateMutex (NULL, FALSE, NULL); |
InitializeCriticalSection(&cs); |
Очистка |
CloseHandle(hmtx); |
DeleteCriticalSection(&cs); |
Бесконечное ожидание |
WaitForSingleObject (hmtx, INFINITE); |
EnterCriticalSection(&cs); |
Ожидание в течение 0 мс |
WaitForSingleObject (hmtx, 0); |
TryEnterCriticalSection (&cs); |
Ожидание в течение произвольного периода времени |
WaitForSingleObject (hmtx, dwMilliseconds); |
Невозможно |
Освобождение |
ReleaseMutex(hmtx); |
LeaveCriticalSection (&cs); |
Возможность параллельного ожидания других объектов ядра |
Да (с помощью WaitForMultipleObjects или аналогичной функции) |
Нет |
