Завершение процесса, заблокировавшего ресурс
Завершение процесса, заблокировавшего ресурс
Когда взаимное исключение используется совместно несколькими процессами, всегда существует возможность, что процесс будет завершен (возможно, принудительно) во время работы с заблокированным им ресурсом. Не существует способа заставить систему автоматически снимать блокировку во время завершения процесса. Мы увидим, что это свойственно и блокировкам чтения-записи, и семафорам Posix. Единственный тип блокировок, автоматически снимаемых системой при завершении процесса, — блокировки записей fcntl (глава 9). При использовании семафоров System V можно специально указать ядру, следует ли автоматически снимать блокировки при завершении работы процесса (функция SEM_UNDO, о которой будет говориться в разделе 11.3).
Поток также может быть завершен в момент работы с заблокированным ресурсом, если его выполнение отменит (cancel) другой поток или он сам вызовет pthread_exit. Последнему варианту не следует уделять много внимания, поскольку поток должен сам знать, блокирует ли он взаимное исключение в данный момент или нет, и в зависимости от этого вызывать pthread_exit. На случай отмены другим потоком можно предусмотреть обработчик сигнала, вызываемый при отмене потока, что продемонстрировано в разделе 8.5. Если же для потока возникают фатальные условия, это обычно приводит к завершению работы всего процесса. Например, если поток делает некорректную операцию с указателем, что приводит к отправке сигнала SIGSEGV, это приводит к остановке всего процесса, если сигнал не перехватывается, и мы возвращаемся к предыдущей ситуации с гибелью процесса, заблокировавшего ресурс.
Даже если бы система автоматически разблокировала ресурсы после завершения процесса, это не всегда решало бы проблему. Блокировка защищала критическую область, в которой, возможно, изменялись какие-то данные. Если процесс был завершен посреди этой области, что стало с данными? Велика вероятность того, что возникнут несоответствия, если, например, новый элемент будет не полностью добавлен в связный список. Если бы ядро просто разблокировало взаимное исключение при завершении процесса, следующий процесс, обратившийся к списку, обнаружил бы, что тот поврежден.
В некоторых случаях автоматическое снятие блокировки (или счетчика — для семафора) при завершении процесса не вызывает проблем. Например, сервер может использовать семафор System V (с функцией SEM_UNDO) для подсчета количества одновременно обслуживаемых клиентов. Каждый раз при порождении процесса вызовом fork он увеличивает значение семафора на единицу, уменьшая его при завершении работы дочернего процесса. Если дочерний процесс завершит работу досрочно, ядро само уменьшит значение семафора. Пример, в котором автоматическое снятие блокировки ядром (а не уменьшение счетчика, как в вышеописанной ситуации) также не вызывает проблем, приведен в разделе 9.7. Демон блокирует один из файлов данных при записи в него и не снимает эту блокировку до завершения работы. Если кто-то попробует запустить копию демона, она завершит работу досрочно, когда обнаружит наличие блокировки на запись. Это гарантирует работу единственного экземпляра демона. Если же демон досрочно завершит работу, ядро само снимет блокировку, что позволит запустить копию демона.
Данный текст является ознакомительным фрагментом.