select() внутри бесконечного цикла использует значительно больше ЦП на виртуальной машине RHEL 4.8, чем на машине Solaris 10.

У меня есть приложение-демон, написанное на C, и в настоящее время оно работает без каких-либо известных проблем на компьютере с Solaris 10. Нахожусь в процессе переноса на линукс. Мне пришлось внести минимальные изменения. Во время тестирования он проходит все тестовые случаи. Проблем с его функциональностью нет. Однако, когда я просматриваю загрузку ЦП в режиме ожидания на моей машине с Solaris, он использует около 0,03% ЦП. На виртуальной машине под управлением Red Hat Enterprise Linux 4.8 тот же процесс использует весь доступный ЦП (обычно где-то в диапазоне 90%+).

Моей первой мыслью было, что что-то не так с циклом событий. Цикл событий представляет собой бесконечный цикл (while(1)) с вызовом select(). Timeval настроен так, что timeval.tv_sec = 0 и timeval.tv_usec = 1000. Это кажется достаточно разумным для того, что делает процесс. В качестве теста я увеличил timeval.tv_sec до 1. Даже после этого я увидел ту же проблему.

Есть ли что-то, что мне не хватает в том, как select работает в Linux и Unix? Или это работает по-разному с ОС, работающей на виртуальной машине? Или, может быть, есть что-то еще, что я полностью упускаю?

Еще одна вещь, я не уверен, какая версия сервера vmware используется. Хотя обновился примерно месяц назад.


person Jake    schedule 12.03.2010    source источник


Ответы (2)


Я считаю, что Linux возвращает оставшееся время, записывая его в параметр time вызова select(), а Solaris этого не делает. Это означает, что программист, не знакомый со спецификацией POSIX, может не сбрасывать параметр времени между вызовами select.

Это приведет к тому, что первый вызов будет иметь тайм-аут 1000 мкс, а все остальные вызовы будут использовать тайм-аут 0 мкс.

person Zan Lynx    schedule 12.03.2010
comment
Великолепно! В этом была проблема. Спасибо! - person Jake; 12.03.2010

Как сказал Zan Lynx, timeval изменяется с помощью select в Linux, поэтому вы должны переназначать правильное значение перед каждым вызовом select. Также я предлагаю проверить, находится ли какой-либо дескриптор файла в определенном состоянии (например, конец файла, одноранговое соединение закрыто...). Возможно, портирование показывает какую-то скрытую ошибку в анализе возвращаемых значений (FD_ISSET и т. д.). Это случилось и со мной несколько лет назад в порте цикла, управляемого выбором: я использовал возвращаемое значение неправильным образом, и в rd_set был добавлен закрытый fd, что привело к сбою выбора. На старой платформе использовался неправильный fd, чтобы иметь значение выше, чем maxfd, поэтому он игнорировался. Из-за той же ошибки программа не распознала ошибку выбора (select() == -1) и зациклилась навсегда.

Пока!

person Giuseppe Guerrini    schedule 12.03.2010
comment
Это очень хороший момент... Я изучаю это сейчас. Спасибо! - person Jon; 13.03.2010