$ <b>./upper < file.txt</b>
THIS IS THE FILE, FILE.TXT, IT IS ALL LOWER CASE.
Что если вы хотите применить этот фильтр из другой программы? Программа useupper.c принимает имя файла как аргумент и откликается сообщением об ошибке при некорректном вызове:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
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; таким способом можно запустить любую исполняемую программу.
$ <b>./useupper file.txt</b>
THIS IS THE FILE, FILE.TXT, IT IS ALL LOWER CASE.
Программа useupper применяет
freopen
для закрытия стандартного ввода и связывания потока файла с файлом, заданным как аргумент программы. Затем она вызывает
execl
, чтобы заменить код выполняемого процесса кодом программы upper. Поскольку файловые дескрипторы сохраняются, пройдя сквозь вызов
execl
, программа upper выполняется так же, как при вводе ее в строке командной оболочки
$ <b>./upper < file.txt</b>
Потоки
Процессы Linux могут взаимодействовать, отправлять друг другу сообщения и прерываться друг другом. Они могут даже организоваться и совместно использовать сегменты памяти, но они остаются обособленными объектами операционной системы. Процессы не настроены на совместное использование переменных.
Существует класс процесса, именуемый потоком (thread), который доступен во многих системах UNIX и Linux. Несмотря на то, что потоки трудно, программировать, они могут быть очень важны для некоторых приложений, таких как многопоточные серверы баз данных. Программирование потоков в Linux (и вообще в UNIX) не так распространено, как применение множественных процессов, поскольку процессы Linux очень легко применять и программирование множественных взаимодействующих процессов гораздо легче программирования потоков. Потоки обсуждаются в главе 12.
Сигналы
Сигнал — это событие, генерируемое системами UNIX и Linux в ответ на некоторую ситуацию, получив сообщение о котором процесс, в свою очередь, может предпринять какое-то действие. Мы применяем термин "возбуждать" (raise) для обозначения генерации сигнала и термин "захватывать" (catch) для обозначения получения или приема сигнала. Сигналы возбуждаются некоторыми ошибочными ситуациями, например нарушениями сегментации памяти, ошибками процессора при выполнении операций с плавающей точкой или некорректными командами. Они генерируются командной оболочкой и обработчиками терминалов для вызова прерываний и могут явно пересылаться от одного процесса к другому как способ передачи информации или коррекции поведения. Во всех этих случаях программный интерфейс один и тот же. Сигналы могут возбуждаться, улавливаться и соответственно обрабатываться или (по крайней мере, некоторые) игнорироваться.
Имена сигналов задаются с помощью включенного заголовочного файла signal.h. Они начинаются с префикса
SIG
и включают приведенные в табл. 11.3 сигналы.
Таблица 11.3
Имя сигнала | Описание |
SIGABORT
| *Процесс аварийно завершается |
SIGALRM
| Сигнал тревоги |
SIGFPE
| *Исключение операции с плавающей точкой |
SIGHUP
| Неожиданный останов или разъединение |
SIGILL
| *Некорректная команда |
SIGINT
| Прерывание терминала |
SIGKILL
| Уничтожение (не может быть перехвачен или игнорирован) |
SIGPIPE
| Запись в канал без считывателя |
SIGQUIT
| Завершение работы терминала |
SIGSEGV
| *Некорректный доступ к сегменту памяти |
SIGTERM
| Завершение, выход |
SIGUSR1
| Сигнал 1, определенный пользователем |
SIGUSR2
| Сигнал 2, определенный пользователем |
*Могут быть также предприняты действия, зависящие от конкретной реализации.
Если процесс получает один из этих сигналов без предварительной подготовки к его перехвату, процесс будет немедленно завершен. Обычно при этом создается файл с дампом ядра. Этот файл в текущем каталоге, названный core, представляет собой образ процесса, который может оказаться полезным при отладке.
К дополнительным относятся сигналы, приведенные в табл. 11.4.
Таблица 11.4
Имя сигнала | Описание |
SIGCHLD
| Дочерний процесс остановлен или завершился |
SIGCONT
| Продолжить выполнение, если процесс был приостановлен |
SIGSTOP
| Остановить выполнение (не может захватываться или игнорироваться) |
SIGTSTP
| Сигнал останова, посылаемый с терминала |
SIGTTIN
| Фоновый процесс пытается читать |
SIGTTOU
| Фоновый процесс пытается писать |