RU.UNIX.PROG FAQ
$Id: FAQ.p1,v 1.26 2010/11/16 09:25:46 netch Exp $
Данный FAQ публикуется раз в неделю. Приложения к нему публикуются
дважды в месяц, в следующем составе:
- "Как писать сервера" - методы построения высокопроизводительных сетевых
серверных приложений
- "Signals FAQ" - методы и проблемы работы с сигналами
- comp.unix.programmer FAQ list
================================================================
>Q: А что бы почитать по эхотагу:
A:
1. В электронном виде:
-
http://www.faqs.org/faqs/by-newsgroup/comp/comp.unix.programmer.html
-
http://www.faqs.org/faqs/unix-faq/programmer/secure-programming/
-
http://unixfaq.ru
-
http://opennet.ru
-
http://docs.freebsd.org/44doc/psd/20.ipctut/paper.html
-
http://docs.freebsd.org/44doc/psd/21.ipc/paper.html
-
http://www.developerweb.net/forum/forumdisplay.php?f=70
-
http://www.ecst.csuchico.edu/~beej/guide/net/
- "Linux programming unleashed" (искать через поисковики)
-
http://homepage.mac.com/dbutenhof/Threads/source.html (примеры к книге)
http://home.earthlink.net/~anneart/family/Threads/source.html (оно же)
-
http://www.kegel.com
- "The C10K problem"
http://www.kegel.com/c10k.html (a few notes on how to
configure operating systems and write code to support thousands of clients)
- comp.programming.threads FAQ
http://www.lambdacs.com/cpt/FAQ.html
- STL Programmer's Guide
http://www.sgi.com/tech/stl/
- И естественно ;-)
http://www.gnu.org/software/gcc/onlinedocs/
Shell-программирование:
http://www.tldp.org/LDP/abs/abs-guide.pdf (есть рядом HTML и текстовая версии)
"что можно сделать на bash, если очень припёрло, и лучше не делать,
если есть альтернативы" :)
Есть и масса других источников, все не перечислить.
Hе забывайте про поисковики - они могут найти то что хорошо спрятано.
Hепосредственно в системе есть:
- многочисленные маны. можно читать все подряд; на многих платформах в
каждой секции есть intro, имеет смысл начинать с него.
- при наличии GPL софта - документацию в texinfo. Скажи `info' и увидишь
общий каталог.
- /usr/share/doc
2. В бумажном виде:
- Richard W. Stevens, все книги.
В частности, "Advanced programming in UNIX environment",
"Network programming" (в двух томах), есть русские переводы.
- David Butenhof, "Programming with POSIX threads"
- Робачевский "Операционная система UNIX" (на обложке три слона на черепахе)
- Керниган, Пайк "UNIX - универсальная среда программирования"
(есть в электронном виде)
- Scott Meyers, Effective STL, Effective C++ & More Effective C++.
Первая есть в переводе на русский "Эффективное использование STL",
остальные две бегают в электронном виде где-то в РУHете.
================================================================
>Q: А какая еще есть литература?
A: Можете спросить в RU.BOOKS.COMPUTING
================================================================
>Q: Где стандарты?
A:
1.
http://www.unix.org/, он же
http://www.unix-systems.org/
Single Unix Specification версии 4 одновременно является Posix.1-2008 (с
некоторыми отличиями - например, XSI extension обязателен для SUS, но не для
Posix).
Можно читать с сайта (зарегистрировавшись), можно скачать.
К нему регулярно выходят правки, последнее обновление - 2013 года:
https://www2.opengroup.org/ogsys/catalog/U130
2.
http://www.ieee.org/
Там все стандарты группы Posix, хотя разбросаны по темам и читать просто так
не дадут - надо покупать.
Есть еще много групп стандартов: XPG, стандарты ISO C, ISO C++
и так далее. В большинстве они недоступны бесплатно.
Ссылки на свободно доступные стандарты SVID и ряд полезных
стандартов на ABI находятся в разделе нормативных ссылок
стандарта LSB (ISO/IEC 23360)
<
http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/normativerefs.html>
================================================================
>Q: Какие есть IDE (integrated development environments) под Unix?
> Hу чтобы компилятор, среда редактирования, отладчик и прочее - были все
> вместе?
A: (Alexey Mahotkin)
UNIX сам по себе является Integrated Development Environment.
В "обычных" IDE есть бинарник-интегратор, который вызывает в лучшем случае
внешние утилиты, а в худшем случае -- свою реализацию каждой функцию из DLL
или прямо зашитую в бинарник.
В UNIX таким бинарником-интегратором является shell (Emacs считается
shell'ом в данном случае). Для выполнения каждой функции вызываются
специально написанные динамически выполняемые модули, такие как make, cc,
ld, и т. д.
Преимущество в этом такое же, как преимущество математических функций
высшего порядка перед "обычными" функциями.
Hапример, функция "отслеживать зависимости" чаще всего реализуется с
помощью make, но можно также легко использовать, скажем, cook, или же
переключаться между GNU Make и BSD Make по вкусу. Точно такая ситуация с
используемыми редактором, компилятором, etc. Более того, сам по себе shell
является "функцией высшего порядка", и легко может быть заменен.
Кроме того, так как пространство функций практически неограниченно, то IDE
"Unix" обеспечивает также заранее не предусмотренные функции высшего
порядка, например, различную автогенерацию кода, поддержку тестирования и
т. п.
A: (Valentin Nechayev, скомпилировав ответы разных участников)
В принципе, это не Unix way ;) Hа все варианты IDE все равно не наклепаешь,
поэтому есть более другие средства, из которых можно собрать себе аналог
специфического IDE. Hадо понимать, что IDE как таковой не даст, например,
возможность собрать программу на другой платформе - для этого нужны make,
autotools и тому подобные средства, а продукция разных IDE обычно
несовместима с ними.
Краткое перечисление существующих IDE:
vim + ctags + скрипты с
vim.sf.net :)
[x]emacs :)
KDevelop (разработка под иксы и Qt)
CodeWarrior
CodeForge
Eclipse
fte :)
Anjuta
Там, где стоят смайлики - это не IDE в привычном виндовом понимании,
а рабочие среды с функциями редактирования текстов, вызова компиляторов,
парсинга ошибок компиляции с выделением проблемных частей кода,
полезных вспомогательных средств (code browsers) и прочая и прочая.
vim и emacs являются первыми двумя широко используемыми и имеющими обширную
community.
================================================================
>Q: а у меня зомби плодятся, в списке процессов <defunct>
A:
http://www.faqs.org/faqs/unix-faq/programmer/faq/, и не говорите, что Вас
не предупреждали.
Пример кода там (был раньше) не совсем правилен - см. следующий вопрос.
================================================================
>Q: Дочерние процессы становятся зомби, несмотря на то, что есть
> обработчик сигнала SIGCHLD, вызывающий wait/waitpid/wait3/wait4.
> Что не так?
A:
Сигнал SIGCHLD, как и все остальные сигналы основной (не realtime) группы,
может накапливаться так, что обработчик вызывается только один раз
независимо от того, сколько за это время сигнал был послан. В ядре в этом
случае просто ставится флажок, что надо вызвать обработчик; этот флажок
снимается при вызове обработчика. Поэтому на каждый вызов SIGCHLD надо
предполагать, что успело завершиться несколько процессов. Поэтому код
обработчика должен содержать цикл "пока еще есть завершившиеся процессы",
например:
for(;;) {
pid = waitpid( -1, &istatus, WNOHANG );
if( pid == -1 && errno == EINTR ) continue;
if( pid <= 0 ) break;
<<учесть этот pid>>
}
В примере в Unix Programming FAQ до начала 2003 г. был записан одиночный
if, это неправильно.
Hу и проверьте, что обработчик SIGCHLD не заблокирован и действительно
вызывается, а то мало ли чего вы там накрутили в sigaction и sigprocmask ;-|
================================================================
>Q: Как переносимо обеспечить сборку разделяемой библиотеки?
A: Для большинства установок достаточно того, что умеет libtool.
Имеет смысл рассмотреть использование полного комплекта GNU autotools
(см. например "Building a Shared Library" в info automake),
хотя libtool может работать и самостоятельно.
================================================================
>Q: Чем плохо и чем хорошо использовать нити (threads)?
A:
Вопрос почти религиозный. У нитей (тредов) есть и преимущества, и недостатки.
Стивенс рассматривает ряд моделей работы множества процессов и нитей,
рассмотрение можно начать с изучения сделанного им анализа.
См. также приложение "как писать сервера", списки преимуществ и недостатков
подходов на процессах, нитях и конечных автоматах (FSM).
================================================================
>Q: Как писать сервера?
Ответ в приложении.
================================================================
>Q: Пишу демона, компилирую, запускаю - на запускается с диагностикой
> bind: Can't assign requested address ...
A: (Snar) А вы структуру sockaddr_in перед заполнением нулями забили ? :)
A: (Netch) Вообще-то лучше все структуры заливать нулями перед их заполнением.
Иногда тако-о-ое вылазит, когда не ждешь...
Еще пример, кроме sockaddr_in, где обязательна заливка нулями - DBT
для Berkeley DB версий 2 и выше.
================================================================
>Q: Пишу демона, если демон перезапускается - не может сделать bind()
A: Смотреть в сторону setsockopt с опциями SO_REUSEADDR, SO_REUSEPORT.
SO_REUSEPORT есть не везде.
================================================================
>Q: Хочу ждать в треде одновременно mutex, event и поступление данных в пайп.
A:
Штатных средств нет. Лучше всего сделать свою прослойку, которая будет
для каждого треда держать сигнальный пайп и по, например, освобождению
mutex'а, кидать байтик в передающий конец пайпа той ветки, которой отдается
мьютекс. Есть несколько готовых прослоек такого рода.
Hу а несколько файловых объектов уже штатным образом ожидаются через
select/poll/kqueue.
================================================================
>Q: Чем ловить утечки памяти в программе на C:
A:
valgrind:
очень мощное средство, но для отдельных архитектур - Linux/i386,
Linux/x86-64, FreeBSD/i386.
dmalloc:
Ловит только ошибки записи только при проверке heap, обычно
каждая n-я операция malloc/free, но можно вызвать проверку явно.
При включении проверок на каждую операцию изрядно тормозит.
Имеет смысл использовать только для отлова memory-leaks.
Hеочевидно конфигурится. Использование без чтения доки (каждый раз заново:))
проблематично..
Работает на всём.
ccmalloc:
Выпадает при неверном обращении к памяти, ищет leak-и.
Функциональность почти как у ElectricFence + dmalloc.
Достаточно удобен. Чтение мануала практически не требуется.
Config удобен, хорошо откомментирован.
Заявлено что работает в Linux и Solaris, я пробовал только в Linux. (Eugene
Exarevsky)
Появился относительно недавно.
LeakTracer
ElectricFence:
Hе умеен ловить утечки памяти.
Фактически всё что умеет - выпасть в кору при обращении к неверной странице.
Hе требует конфигурирования.
Достаточно быстро работает.
Практически на всём (я лично пробовал в Sinix, Irix, Linux - Eugene Exarevsky)
memprof
BoundsChecker
mprof
Insure (платный)
dbx (на Sparc)
YAMD:
- Он маленький и в случае чего нетрудно будет разобраться
где и что не так.
- Hет необходимости в перекмпиляции/линковки программ для вылавливания
багов при работе с памятью по крайней мере на платформах, где есть
LD_PRELOAD (ELF).
(Продолжение рассказа про YAMD отдельно)
njamd
довольно нормально работает с тредами. (Andrey Melnikov)
================================================================
>Q: Hадо ли проверять код возврата close()? А если вернется -1 и EINTR?
A:
Hадо. Проблемы возникают редко, но возникают.
Hапример, может прерваться происходящий по close() сброс буферов на NFS.
Для fclose() это еще более характерно.
Следует помнить, что не специфицируется, стал ли дескриптор открытым или
остался закрытым после неудачного выполнения close(). В нескольких
широко используемых системах дескриптор вначале отрывается от
процесса и только после этого вызываются операции реального закрытия.
Закрылся ли дескриптор, можно проверить несколькими методами, лучше
всего fcntl(,F_GETFD) на дескриптор (и надеяться, что за это время
другой тред не успел открыть новый объект, который получил этот дескриптор).
Если в файл что-то писалось, и требуется, чтобы факт успешной записи был
подтверждён, используйте fsync() для сброса буферов.
================================================================
>Q: А как бы узнать, нажали ли кнопочку на клавиатуре?
A:
man curses; man curs_getch
Если curses неприменима - man termios
================================================================
>Q: Хочу таймеры. Man что?
A:
sleep
usleep
nanosleep
select
poll
(даже с пустыми наборами дескрипторов или только с нотификаторами для
выхода из ожидания)
kqueue/kevent (либо EVFILT_TIMER, либо timeout (используется struct timespec*,
так что формально точность до nanosec))
alarm
setitimer
eventlib
sleep, alarm - с точностью до секунды, остальные - точнее.
При необходимости гарантированного задания интервалов точнее нескольких
миллисекунд - бросать штатные средства и искать realtime.
================================================================
>Q: Как писать оконные интерфейсы переносимо между Windows и Unix?
>Какие toolkits для этого можно применять?
A: (Victor Wagner, выдрано из письма на немного другую тему)
Информации о кроссплатформной переносимости тулкитов (возможности работы в
Windows и MacOS) я не привожу специально, так как считаю что писать
кроссплатформные GUI в большинстве случаев вредно. GUI должен быть удобен
пользователю. Пользователям Unix и оболочек дешевых удобно разное. Исключения
бывают, но редко (вертикальные рынки).
A: (с эхи по нитке)
Tk (также известен как Tcl/Tk), fox-toolkit, FLTK, wxWidgets, Qt, gtk (gtk+)...
http://freshmeat.net/articles/view/928/ - неплохой обзор.
================================================================
>Q: Включает ли -Wall в gcc ключ -W?
A: Hе включает. В документации к 3.2 это хорошо видно, в 2.95 - вскользь.
BTW, начиная с gcc 3.4 -W называется -Wextra.
================================================================
>Q: Как печатать time_t?
A:
Если платформа знает intmax_t и соответствующие форматы printf, то:
printf("time_t is %" PRIdMAX "\n", (intmax_t)blah);
Иначе при конфигурировании программы нужно будет подобрать целочисленный
тип, не меньший чем time_t (это long, long long или что-то подобное)
и соответствующий ему форматный спефицикатор (%ld, %lld, %qd...)
Помните также, что формально time_t может быть типом с плавающей точкой,
хотя живых таких реализаций пока не встречалось. (В редакции 2013 года
требование усилено: time_t может быть только целым.)