Re: fprintf && write

From
Boris Rudakov (2:5054/9.4)
To
Andrey Melnikov ()
Date
2003-06-05T11:04:50Z
Area
RU.UNIX.PROG
Hello Andrey!

04 июн 03 13:18, you wrote to me:

 AM>                                Hello Boris!


 AM>  04 Jun 03 10:57, Boris Rudakov wrote to Andrey Melnikov:
 AM>>> Что-то у меня лыжи не едут совсем.

 AM>>> Выкидываю все эти fprintf() и заменяю на свою функцию:
[...]
 AM>>> static char wr_buf[1024];

 BR>> Для теста - прокатит, а вообще стоит избегать глобальных
 BR>> переменных. Я нахожу что весь код нужно писать реентерабельным.
 BR>> Если нет ОСОБЫХ причин делать иначе :) Я бы этот буфер увеличил
 BR>> раза в 4 и засунул внутрь функции
 BR>> :)
 AM>     Дороже выйдет. Войти в процедуру, отрезать кусок стека. Выйти -
 AM> подчистить.
Да брось, ты чего ?!
У тебя и так есть локальные переменные - значит стековый кадр в любом случае будет формироваться: на Интелах их слишком много чтобы ограничиться одними регистровыми, да и наличие вложенных вызовов других функций требует где-то сохранять значения на время вызова. Стопудово - стековый кадр будет. Создаетя он (обычно) одним единственым SUB ESP, FrameSize - это один такт :) И какого размера и сколько переменных включает в себя этот FrameSize - похеру. Ты ничего не теряешь.

 AM> Код у меня не реентрабельный - задача того не требует.
Эээээээ, ПЛОХАЯ идея :):):):)

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

Лучше всегда оперировать "типично-хорошими" решениями. Реентерабельность - "типично-хорошее" решение.

Через цать времени тебе взбредет эту или аналогичную функцию заюзать в многонитевой программе. Налетишь на грабли. Будешь искать. Найдешь. Будешь материться, перенесешь переменную внутрь функции. Спрашивается - нафига козе баян ? :) Почему сразу же было ее туда не засунуть ?

Писать надо провереными штампами, отдавая предпочтение проверенным и "в общем случае более правильным" ходам.

 BR>> 2. Кроме write у тебя есть только один вызов API - select (в
 BR>> Виндах я бы сказал "Вызов функции ядра", но думаю что и тут с
 BR>> select этот термин будет точен). Морал - тормозит (сверх
 BR>> ожидаемого) он.
 AM>     Наверное - слово тормозит здесь не самое уместное. Я бы сказал -
 AM> чаще делиться временем со всеми остальными задачами. Или я неправ ?

Думаю что неправ.

Система работает в режиме вытесняющей многозадачности. Ей похеру что делает твой процесс - вышел квант и амба, пошел работать другой процесс (точнее - нить). Место в котором уснула твоя нить (в своем коде или внутри системного вызова) роли не играет.

 BR>> Моя теория такова (еще раз шаркну ножкой что я не юниксоид, но
 BR>> основные принципы едины):
 BR>> * Твой код делает два системных вызова.
 AM>     Да. Но без них - у меня два варианта:

 AM> 1. Получить засыпание при вызове fprintf(...) где-то в ядре на
 AM> write(..) на очень большое время, что увы неприемлимо. 2. Использовать
 AM> alarm(time), write()/fprintf(), alarm(0); - я получу 3 системных
 AM> вызова.

Давай разберемся чего тебе надо.

1. Если тебе надо просто чего-то вывести в файл (приведенный тобой пример делает это и ничего кроме этого) то сугубо пофигу как ты это делаешь. Есть два варианта:
1.1. Ты вызываешь один блокирующий синхронный вызов (write) и получаешь управлеие назад когда все закончено.
1.1. Ты делаешь асинхроный вызов и потом ждешь когда он завершится.

Вопрос: а нахера ? Какая разница ? Если ты ждешь только завершения IO, то на кой городить огород когда write сделает за тебя это же самое ?!

Я бы понял вариант номер 2:

2. Ты инициируешь асинхронное IO и, параллельно с его работой, делаешь чего-то еще, временами интересуясь как там насчет завершения.

В предыдущей мессаге я как-раз привел подобный код, написанный под НТю с просьбой растусовать как такое делается в юниксах. Там-то задача не просто инициировать IO и дождаться его завершения (тогда мне бы хватило синхронного блокирующего режима ReadFile), но и поймать возможную команду "кансел все нахер" - взведения специального ивента hStopEvent.

Только во втором варианте имеет смысл развлекаться со специальными средствами контроля асинхронных операций IO. В твоем примере такой потребности ну никак не прослеживалось :):):)


Кста, чисто информации для: не знаю как в юниксах, а в НТе многие синхронные операции IO на самом деле - врапперы над асинхронными функциями API. Пример - сокеты. Ядро открывает сокеты всегда в асинхронном и только асинхронном режиме доступа. Если работать с ними основными функциями IO ReadFile/WriteFile, но не передавать структуру OVERLAPPED (она служит для контроля асинхронного IO и если вместо нее подсовывать NULL то это означает что ты желаешь чтобы вызов был блокирующим) то система говорит ERROR_INVALID_PARAMETER - иди, мол, лесом. OVERLAPPED давай. Экспериментально установлено что НТевые реализации send/recv - примитивнейшие врапперы над ReadFile/WriteFile, внутри ожидающие завершения асинхронного IO над сокетами.

Сдается мне что если у тебя нет потребности одновременно с ожиданием завершения асинхронной операции делать чего-то еще, то нет никаких оснований брать на себя задачи синхронизации. Пусть ими занимается API.

У меня, например, в одном из достаточно сложных модулей управления IO (для серверных приложений) со всеми типами файлов, включая сокеты, используются базовые асинхронные средства IO, и никаких врапперов типа синхронных send/recv. Но там у рабочих нитей и задача соотвествующая - ждать не только результатов прокачки данных, но и значительного количества разных управляющих событий.

Ты уверен что у тебя такая же задача и тебе реально нужно чего-то делать одновременно с ожиданием завершения IO ? Из примера следует обратное :)

 BR>> Таким образом, сдается мне что двукратное замедление вызвано тем,
 BR>> что ты в два раза чаще беспокоишь ядро системы :)
 AM>     А вот такой вот я плохой - забочусь об состоянии endpoint'a...

В твоем примере нигде не видно двух вещей:

1. Потребности делать что-то параллельно с IO.
2. Потребности прервать IO.

Любой из них достаточно чтобы включать асинхронный режим и вручную контроллировать его завершение.

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

 AM>      Andrey aka TEMHOTA-RIPN

Борис Рудаков,               Если долго мучиться -
BBR                          что-нибудь получится !

--- Be happy: BBR is looking at you !
 * Origin: АлкАголь малыми дозами безвреден в любых количествах (2:5054/9.4)