Нейл Мэтью - Основы программирования в Linux
- Название:Основы программирования в Linux
- Автор:
- Жанр:
- Издательство:«БХВ-Петербург»
- Год:2009
- Город:Санкт-Петербург
- ISBN:978-5-9775-0289-4
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Нейл Мэтью - Основы программирования в Linux краткое содержание
В четвертом издании популярного руководства даны основы программирования в операционной системе Linux. Рассмотрены: использование библиотек C/C++ и стандартных средств разработки, организация системных вызовов, файловый ввод/вывод, взаимодействие процессов, программирование средствами командной оболочки, создание графических пользовательских интерфейсов с помощью инструментальных средств GTK+ или Qt, применение сокетов и др. Описана компиляция программ, их компоновка c библиотеками и работа с терминальным вводом/выводом. Даны приемы написания приложений в средах GNOME® и KDE®, хранения данных с использованием СУБД MySQL® и отладки программ. Книга хорошо структурирована, что делает обучение легким и быстрым.
Для начинающих Linux-программистов
Основы программирования в Linux - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Вы сможете увидеть создание процесса-зомби, если измените количество сообщений в программе из примера с вызовом fork
. Если дочерний процесс выводит меньше сообщений, чем родительский, он закончится первым и будет существовать как зомби, пока не завершится родительский процесс.
Программа fork2.c такая же, как программа fork1.с, за исключением того, что количества сообщений, выводимых родительским и дочерним процессами, поменяли местами. Далее приведены соответствующие строки кода:
switch (pid) {
case -1:
perror("fork failed");
exit(1);
case 0:
message = "This is the child";
n = 3;
break;
default:
message = "This is the parent";
n = 5;
break;
}
Как это работает
Если вы выполните только что приведенную программу с помощью команды ./fork2 &
и затем вызовите программу ps
после завершения дочернего процесса, но до окончания родительского, то увидите строку, подобную следующей. (Некоторые системы могут сказать вместо .)
$ ps -аl
F S UID PID PPID С PRI NI ADDR SZ WCHAN TTY TIME CMD
004 S 0 1273 1259 0 75 0 - 589 wait4 pts/2 00:00:00 su
000 S 0 1274 1273 0 75 0 - 731 schedu pts/2 00:00:00 bash
000 S 500 1463 1262 0 75 0 - 788 schedu pts/1 00:00:00 oclock
000 S 500 1465 1262 0 75 0 - 2569 schedu pts/1 00:00:01 emacs
000 S 500 1603 1262 0 75 0 - 313 schedu pts/1 00:00:00 fork2
003 Z 500 1604 1603 0 75 0 - 0 do_exi pts/1 00:00:00 fork2
000 R 500 1605 1262 0 81 0 - 781 - pts/1 00:00:00 ps
Если родительский процесс завершится необычно, дочерний процесс автоматически получит в качестве родителя процесс с PID, равным 1 (init). Теперь дочерний процесс — зомби, который уже не выполняется, но унаследован процессом init
из-за необычного окончания родительского процесса. Зомби останется в таблице процессов, пока не пойман процессом init
. Чем больше таблица, тем медленнее эта процедура. Следует избегать процессов-зомби, поскольку они потребляют ресурсы до тех пор, пока процесс init не вычистит их.
Есть еще один системный вызов, который можно применять для ожидания дочернего процесса. Он называется waitpid
и применяется для ожидания завершения определенного процесса.
#include
#include
pid_t waitpid(pid_t pid, int *stat_loc, int options);
Аргумент pid
— конкретный дочерний процесс, окончания которого нужно ждать. Если он равен –1, waitpid
вернет информацию о любом дочернем процессе. Как и вызов wait
, он записывает информацию о состоянии процесса в место, указанное аргументом stat_loc
, если последний не равен пустому указателю. Аргумент options
позволяет изменить поведение waitpid
. Наиболее полезная опция WNOHANG
мешает вызову waitpid
приостанавливать выполнение вызвавшего его процесса. Ее можно применять для выяснения, завершился ли какой-либо из дочерних процессов, и если нет, то продолжать выполнение. Остальные опции такие же, как в вызове wait
.
Итак, если вы хотите, чтобы родительский процесс периодически проверял, завершился ли конкретный дочерний процесс, можно использовать следующий вызов:
waitpid(child_pid, (int *)0, WNOHANG);
Он вернет ноль, если дочерний процесс не завершился и не остановлен, или child_pid
, если это произошло. Вызов waitpid вернет -1 в случае ошибки и установит переменную errno
. Это может произойти, если нет дочерних процессов ( errno
равна ECHILD
), если вызов прерван сигналом ( EINTR
) или аргумент options
неверный ( EINVAL
).
Перенаправление ввода и вывода
Вы можете применить ваши знания о процессах для изменения поведения программ, используя тот факт, что открытые файловые дескрипторы сохраняются вызовами fork
и exec
. Следующий пример из упражнения 11.6 содержит программу-фильтр, которая читает из стандартного ввода и пишет в свой стандартный вывод, выполняя при этом некоторое полезное преобразование.
Далее приведена программа очень простой фильтрации upper.c, которая читает ввод и преобразует строчные буквы в прописные:
#include
#include
#include
int main() {
int ch;
while ((ch = getchar()) != EOF) {
putchar(toupper(ch));
}
exit(0);
}
Когда вы выполните программу, она сделает то, что и ожидалось:
$ ./upper
hello THERE
HELLO THERE
^D
$
Вы, конечно, можете применить ее для преобразования символов файла, используя перенаправление, применяемое командной оболочкой:
$ cat file.txt
this is the file, file.txt, it is all lower case.
$ ./upper < file.txt
THIS IS THE FILE, FILE.TXT, IT IS ALL LOWER CASE.
Что если вы хотите применить этот фильтр из другой программы? Программа useupper.c принимает имя файла как аргумент и откликается сообщением об ошибке при некорректном вызове:
#include
#include
#include
int main(int argc, char *argv[]) {
char *filename;
if (argc != 2) {
fprintf (stderr, "usage: useupper file\n");
exit(1);
}
filename = argv[1];
Вы повторно открываете стандартный ввод, снова при этом проверяете наличие любых ошибок, а затем применяете функцию execl
для вызова программы upper:
if (!freopen(filename, "r", stdin)) {
fprintf(stderr, "could not redirect stdin from file %s\n", filename);
exit(2);
}
execl("./upper", "upper", 0);
He забудьте, что execl
заменяет текущий процесс, если ошибок нет, оставшиеся строки не выполняются.
perror("could not exec ./upper");
exit(3);
}
Как это работает
Когда вы выполняете эту программу, ей можно передать файл для преобразования в прописные буквы. Работа делается программой upper, которая не обрабатывает аргументы с именами файлов. Обратите внимание на то, что вам не нужен исходный код программы upper; таким способом можно запустить любую исполняемую программу.
$ ./useupper file.txt
THIS IS THE FILE, FILE.TXT, IT IS ALL LOWER CASE.
Программа useupper применяет freopen
для закрытия стандартного ввода и связывания потока файла с файлом, заданным как аргумент программы. Затем она вызывает execl
, чтобы заменить код выполняемого процесса кодом программы upper. Поскольку файловые дескрипторы сохраняются, пройдя сквозь вызов execl
, программа upper выполняется так же, как при вводе ее в строке командной оболочки
Интервал:
Закладка: