> 返回资讯列表
news_article.exe
📰

Я убил процесс и дренаж еще висел: внучка держала трубу

I killed the process and the drain still hung: a grandchild held the pipe

2026年9月6日6 次浏览来源:Dev.to 阅读原文

Моя программа висела сорок минут. Не вращается при тысяче циклов в секунду: при нулевом проценте процессора. Он не делал слишком много работы; он не делал никакой работы вообще. И все равно это не закончится. Программа делает что-то общее: она организует внешние инструменты командной строки. Он запускает один, читает то, что записывает на стандартный вывод, и переходит к следующему, когда он сделан. Таким образом, он не застревает, когда инструмент тащит, у каждого есть тайм-аут: когда он загорается, процесс убивается, и мы продолжаем. Это та часть, которая провалилась, и она провалилась там, где никто не смотрит: после убийства процесса. Убийство процесса не закрывает трубу Когда вы читаете вывод подпроцесса, вы читаете из трубы: один конец пишет (подпроцесс), другой читает (вы). Ваш читатель не закончит, когда подпроцесс...

Моя программа висела сорок минут. Не вращается при тысяче циклов в секунду: при нулевом проценте процессора. Он не делал слишком много работы; он не делал никакой работы вообще. И все равно это не закончится. Программа делает что-то общее: она организует внешние инструменты командной строки. Он запускает один, читает то, что записывает на стандартный вывод, и переходит к следующему, когда он сделан. Таким образом, он не застревает, когда инструмент тащит, у каждого есть тайм-аут: когда он загорается, процесс убивается, и мы продолжаем. Это та часть, которая провалилась, и она провалилась там, где никто не смотрит: после убийства процесса. Убийство процесса не закрывает трубу Когда вы читаете вывод подпроцесса, вы читаете из трубы: один конец пишет (подпроцесс), другой читает (вы). Ваш читатель не закончит, когда подпроцесс умрет. Он заканчивается, когда EOF прибывает, а EOF трубы прибывает только тогда, когда последняя запись заканчивается. Почти всегда они совпадают: подпроцесс — единственный писатель, он умирает, его конец закрывается, приходит EOF, ваш читатель заканчивает. Все в микросекундах. Но «почти всегда» — это не «всегда». Инструмент, который я запустил, запустил еще один — внука. И этот внук унаследовал конец записи трубки, потому что на Unix ребенок наследует открытые дескрипторы своих родителей, если не указано иное. Поэтому, когда тайм-аут выстрелил, я убил ребенка. Его конец закрыт. Но внук был еще жив, с открытой копией дескриптора. Последняя запись не закрывалась. ЭОФ так и не пришел. И мой читатель сидел в ожидании EOF, который никогда не появится — на нулевом проценте процессора, заблокированном в , неотличимом от медленной работы. Симптом, который обманывает Что делает эту неудачу настолько трудной, так это то, что она не выглядит как неудача. Бесконечная цепь сжигает процессор: вы видите его мгновенно. Этот ничего не тратит. Нить спит в ядре в ожидании данных, которые не приходят. В этом списке он выглядит здоровым. В метриках это выглядит как «некоторое время». Единственный способ сказать «подвешенный навсегда» от «бегущий медленно» — посмотреть на стек ниток и увидеть, что никогда не движется. Ремонт не убивает лучше Рефлекс заключается в том, чтобы попытаться убить внуков — процессную группу, сеанс, целое дерево. Иногда можно, иногда нельзя: процесс может вырваться из группы, внук может нарочно пережить своего родителя. Но есть более простой и честный выход, и он исходит из одного вопроса: какой именно процесс закроет этот дескриптор? Если ответ «ничто, что я контролирую», то ожидание EOF — это ожидание чего-то, что не произойдет. И ожидание чего-то, что не произойдет, не фиксируется ожиданием лучше: оно ограничено. Решение состояло в том, чтобы установить тайм-аут на саму дренаж. После завершения процесса мы ждем EOF в течение нескольких секунд; если он не приходит, мы отказываемся от чтения и двигаемся дальше. Что бы инструмент не успел написать раньше, он уже захвачен, поэтому ничего не теряется. И дескриптор внук держит открытыми остановки имеет значение: никто не ждет на нем бесконечно. Каждое ожидание — петля, которая вращается до тех пор, пока не выдержит условие, на дескриптор — имеет один вопрос: какой процесс сделает это условие истинным? Если нет, ожидание невозможно, и невозможное ожидание не дает ошибки: оно выглядит точно так же, как работа, которая занимает некоторое время. Нулевой процент процессора, а не прогресс, навсегда. Прежде чем написать ожидание, назовите процесс, который его завершит. Если вы не можете назвать его, не пишите его без кепки.

> 分享: