Марк Митчелл - Программирование для Linux. Профессиональный подход

Скачивание начинается... Если скачивание не началось автоматически, пожалуйста нажмите на эту ссылку.
Жалоба
Напишите нам, и мы в срочном порядке примем меры.
Описание книги "Программирование для Linux. Профессиональный подход"
Описание и краткое содержание "Программирование для Linux. Профессиональный подход" читать бесплатно онлайн.
Данная книга в основном посвящена программированию в среде GNU/Linux. Авторы применяют обучающий подход, последовательно излагая самые важные концепции и методики использования расширенных возможностей системы GNU/Linux в прикладных программах. Читатели научатся писать программы, к интерфейсу которых привыкли пользователи Linux; освоят такие технологии, как многозадачность, многопотоковое программирование, межзадачное взаимодействие и взаимодействие с аппаратными устройствами; смогут улучшить свои программы, сделав их быстрее, надежнее и безопаснее; поймут особенности системы GNU/Linux, ее ограничения, дополнительные возможности и специфические соглашения.
Книга предназначена для программистов, уже знакомых с языком С и имеющих базовый опыт работы в GNU/Linux.
Сказанное иллюстрирует программа thread-pid, показанная в листинге 4.15. Она отображает идентификатор главного потока с помощью функции getpid() и создает новый поток, в котором тоже выводится значение идентификатора, после чего оба потока входят в бесконечный цикл.
Листинг 4.15. (thread-pid.c) Вывод идентификаторов потоков#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
void* thread_function(void* arg) {
fprintf(stderr, "child thread pid is %d\n", (int) getpid());
/* Бесконечный цикл. */
while (1);
return NULL;
}
int main() {
pthread_t thread;
fprintf(stderr, "main thread pid is %d\n", (int)getpid());
pthread_create(&thread, NULL, &thread_function, NULL);
/* Бесконечный цикл. */
while (1);
return 0;
}
Запустите программу в фоновом режиме, а затем вызовите команду ps x, чтобы увидеть список выполняющихся процессов. Не забудьте затем уничтожить программу thread-pid, так как она потребляет ресурсы процессора. Вот что мы получим:
% cc thread-pid.c -о thread-pid -lpthread
% ./thread-pid &
[1] 14608
main thread pid is 14608
child thread pid is 14610
% ps x
PID TTY STAT TIME COMMAND
14042 pts/9 S 0:00 bash
14068 pts/9 R 0:01 ./thread-pid
14069 pts/9 S 0:00 ./thread-pid
14610 pts/9 R 0:01 ./thread-pid
14611 pts/9 R 0:00 ps x
% kill 14608
[1]+ Terminated ./thread-pid
Сообщения интерпретатора команд» касающиеся управления заданиямиСтроки, начинающиеся с записи [1], поступают от интерпретатора команд. Если программа запускается в фоновом режиме, интерпретатор назначает ей номер задания — в данном случае 1 — и сообщает ее идентификатор. Когда фоновое задание завершается, интерпретатор сообщает об этом при вызове первой же команды
Обратите внимание на то, что программе thread-pid соответствуют три процесса. Первый из них, с идентификатором 14608, — это основной поток программы. Третий, с идентификатором 14610, — это дочерний поток, выполняющий функцию thread_function(). Что же такое тогда второй поток, с идентификатором 14609? Это "управляющий поток", являющийся частью внутреннего механизма реализации потоков в Linux. Он создается, когда программа вызывает функцию pthread_create().
4.5.1. Обработка сигналов
Предположим, что многопотоковая программа принимает сигнал. В каком потоке будет вызван обработчик сигнала? Это зависит от версии UNIX. В Linux поведение программы объясняется тем. что потоки на самом деле реализуются в виде процессов.
Каждый поток в Linux является отдельным процессом, а сигнал доставляется конкретному процессу, поэтому никакой неоднозначности на самом деле нет. Обычно сигнал, поступающий от внешней программы, посылается процессу, управляющему главным потоком программы. Например, если программа с помощью функции fork() делится на два процесса и дочерний процесс запускает многопотоковую программу, в родительском процессе будет храниться идентификатор главного потока дочернего процесса, и этот идентификатор будет включаться во все сигналы, посылаемые от предка потомку. Этим правилом следует руководствоваться при написании многопотоковых программ для Linux.
Тем не менее подобная особенность реализации библиотеки Pthreads в Linux не согласуется со стандартом POSIX. Нельзя полагаться на нее в программах, рассчитанных на то, чтобы быть переносимыми.
В многопотоковой программе один поток может послать сигнал другому. Для этого предназначена функция pthread_kill(). Ее первым параметром является идентификатор потока, а второй параметр — это номер сигнала.
4.5.2. Системный вызов clone()
Все потоки, создаваемые в одной программе, являются отдельными процессами, которые делят общее адресное пространство и другие ресурсы. Но дочерний процесс, создаваемый с помощью функции fork(), получает в свое распоряжение копии ресурсов. Как же реализуются процессы первого типа?
В Linux имеется функция clone(), являющаяся обобщением функций fork() и pthread_create(). Она позволяет вызывающему процессу указывать, какие ресурсы он согласен делить с дочерним процессом. Необходимо также задать область памяти, в которой будет расположен стек выполнения нового процесса. Вообще говоря, мы упоминаем функцию clone() лишь для того, чтобы удовлетворить любопытство читателей. Использовать ее в программах не следует. Создавайте процессы с помощью функции fork(), а потоки — с помощью функции pthread_create().
4.6. Сравнение процессов и потоков
В некоторых программах, связанных с параллельным выполнением операций, сделать выбор в пользу процессов или потоков может оказаться достаточно сложно. Приведем рад правил, которые помогут читателям выбрать наилучшую модель для своих программ.
■ Все потоки программы должны выполнять один и тот же код. В то же время дочерний процесс может запустить другой исполняемый файл с помощью функции exec().
■ Неправильно работающий поток способен помешать другим потокам того же процесса, поскольку все они используют одни и те же ресурсы. Например, неверное обращение к указателю может привести к искажению области памяти, используемой другим потоком. Процесс лишен возможности это делать, так как у него своя копия памяти,
■ Копирование памяти, требуемой для дочернего процесса, приводит к снижению производительности процессов в сравнении с потоками. Но на самом деле операция копирования выполняется только тогда, когда содержимое памяти изменяется, поэтому снижение производительности оказывается минимальным, если дочерний процесс обращается к памяти только для чтения данных.
■ Потоки требуются программам, в которых необходима тонкая настройка параллельной работы. Потоки, например, хорошо подходят в том случае, когда задание можно разбить на ряд почти идентичных задач. Процессы в основном работают не зависимо друг от друга.
■ Совместное использование данных несколькими потоками — тривиальная задача, ведь потоки имеют общий доступ к ресурсам (необходимо, правда, внимательно следить за тем, чтобы не возникало состояние гонки). В случае процессов требуется задействовать особый механизм взаимодействия, описанный в главе 5, "Взаимодействие процессов". Это делает программы более громоздкими, зато уменьшает вероятность ошибок, связанных с параллельной работой.
Глава 5
Взаимодействие процессов
В главе 3, "Процессы", описывалась процедура создания процесса и рассказывалось о том, как родительский процесс может получить код завершения дочернего процесса. Это простейшая форма взаимодействия двух процессов, но не самая эффективная. Рассмотренные в главе 3 механизмы позволяли процессу-предку общаться с процессом-потомком только посредством аргументов командной строки и переменных среды, а все, что мог сделать для предка потомок, — вернуть свой код завершения. Такие механизмы не позволяют контролировать выполняющийся процесс или обращаться к внешнему, независимому процессу.
В этой главе будет показано, как обойти упомянутые ограничения путем организации взаимодействия процессов. Между собой могут общаться не только родительский и дочерний процессы, но также "неродственные" процессы и даже процессы, выполняющиеся на разных компьютерах.
Взаимодействие процессов — это механизм обмена данными между процессами. Взять, к примеру, ситуацию, когда броузер запрашивает Web-страницу у сервера, который в ответ высылает HTML-данные. Обычно при этом используются сокеты, работающие через телефонное соединение. Или другой пример: пользователь вводит команду ls | lpr, чтобы вывести на печать список файлов в каталоге. Интерпретатор команд создает два отдельных процесса — ls и lpr — и соединяет их каналом, который представлен символом '|'. Канал — это однонаправленный способ передачи данных от одного процесса к другому. Процесс ls записывает данные в канал, а процесс lpr читает данные из него.
В этой главе рассматриваются пять способов взаимодействия процессов.
■ Совместно используемая память — процессы могут просто читать и записывать данные в рамках заданной области памяти.
■ Отображаемая память — напоминает совместно используемую память, но организуется связь с файлами.
■ Каналы — позволяют последовательно передавать данные от одного процесса к другому.
■ FIFO-файлы — в отличие от каналов, с ними работают несвязанные процессы, поскольку у такого файла есть имя в файловой системе и к нему может обратиться любой процесс.
Подписывайтесь на наши страницы в социальных сетях.
Будьте в курсе последних книжных новинок, комментируйте, обсуждайте. Мы ждём Вас!
Похожие книги на "Программирование для Linux. Профессиональный подход"
Книги похожие на "Программирование для Linux. Профессиональный подход" читать онлайн или скачать бесплатно полные версии.
Мы рекомендуем Вам зарегистрироваться либо войти на сайт под своим именем.
Отзывы о "Марк Митчелл - Программирование для Linux. Профессиональный подход"
Отзывы читателей о книге "Программирование для Linux. Профессиональный подход", комментарии и мнения людей о произведении.