Как блокировать fprintf в Linux? - PullRequest
1 голос
/ 24 ноября 2010

У меня есть вызов fprintf, который блокируется в течение примерно 10 секунд безосновательно, когда система занята вводом-выводом, но все еще имеет много ЦП.Я не setvbuf основного потока и не открыл базовый FD с O_DIRECT.Это означает, что у потока есть и поток stdio, и системный кэш.

Я не могу сказать, как может блокироваться вызов fprintf на такой длительный период.В худшем случае, когда буфер потока основного потока заполнен, я думаю, что libc просто вызывает write(2), чтобы записать содержимое буфера на диск.Но, насколько мне известно, write(2) на fd, который не открывается с помощью O_DIRECT, не будет ждать передачи диска, то есть он асинхронен относительно дискового ввода-вывода.Таким образом, единственная трудоемкая работа, о которой я мог подумать, - это выделение ядром кэша для записанных данных, но это не похоже на 10-секундную работу, даже когда системе не хватает памяти.На самом деле, система имеет десятки МБ свободной памяти и несколько ГБ кэш-памяти.

Есть какой-нибудь совет?

Спасибо.

Ответы [ 4 ]

0 голосов
/ 25 ноября 2010

Если ваш процесс записывает большие объемы данных на диск, он создаст много грязных страниц в кеше страниц, и write() в конечном итоге заставит ваш процесс выполнить синхронную обратную запись для некоторых из этих страниц.В этой ситуации ядро ​​не вернется к вашему процессу до тех пор, пока не будет записано достаточное количество данных на диск (хотя 10 секунд все еще звучат немного высоко).

0 голосов
/ 24 ноября 2010

Вызов записи не является асинхронным, то есть системный вызов должен возвращаться из ядра. Конечно, этот системный вызов, в основном, помещает данные в очередь ввода / вывода, которая позже осуществит реальную передачу. Тем не менее, я думаю, что эта очередь ввода / вывода может быть недоступна в течение некоторого времени.

Это не зависит от носителя, на который вы пишете, если это блочное устройство. У меня есть программа записи потоков изображений JPEG на SD-карту. Эта программа зависнет из-за операций на жестком диске.

Однако, если это проблема с блокировкой вызова записи в течение десяти секунд, вы можете попытаться ограничить вашу программу. Я не знаю, как или если это нарушит поведение, которое вы пытаетесь наблюдать

strace -T -e trace=write progname

Если вы хотите отслеживать активность журнала, возможно, вы можете перенаправить запись журнала в канал или именованный канал, поместить процесс, который по сути читает из этого канала и записывает в ваш файл журнала, и связать его. *

0 голосов
/ 24 ноября 2010

Вы сказали, что не вызывали setvbuf() в потоке, но какой тип буферизации использует поток? Если поток, который вы используете, не равен stderr (или иногда stdout), он будет буферизован по умолчанию, что означает, что никакие записи не будут выполняться, пока буфер не заполнится (обычно 4096 байт или более). В зависимости от того, как часто вы пишете журналы, это может привести к 10-секундной задержке.

Итак, я бы попробовал: setvbuf(my_stream, NULL, _IONBF, 0);

РЕДАКТИРОВАТЬ: ... Или, возможно, я полностью неверно истолковал слово "заблокировано". В любом случае, на всякий случай.

0 голосов
/ 24 ноября 2010

Вы запускали свой код на более чем одной машине? Если так, то поведение такое же?

Если нет, проверьте ошибки доступа к диску в журнале вашей системы, как только у меня возникла похожая проблема и причиной стал неисправный диск.

...