Нейл Мэтью - Основы программирования в Linux
- Название:Основы программирования в Linux
- Автор:
- Жанр:
- Издательство:«БХВ-Петербург»
- Год:2009
- Город:Санкт-Петербург
- ISBN:978-5-9775-0289-4
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Нейл Мэтью - Основы программирования в Linux краткое содержание
В четвертом издании популярного руководства даны основы программирования в операционной системе Linux. Рассмотрены: использование библиотек C/C++ и стандартных средств разработки, организация системных вызовов, файловый ввод/вывод, взаимодействие процессов, программирование средствами командной оболочки, создание графических пользовательских интерфейсов с помощью инструментальных средств GTK+ или Qt, применение сокетов и др. Описана компиляция программ, их компоновка c библиотеками и работа с терминальным вводом/выводом. Даны приемы написания приложений в средах GNOME® и KDE®, хранения данных с использованием СУБД MySQL® и отладки программ. Книга хорошо структурирована, что делает обучение легким и быстрым.
Для начинающих Linux-программистов
Основы программирования в Linux - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
В функции main
объявлено несколько переменных и затем осуществляется вызов функции pthread_create
, чтобы начать выполнение нового потока.
pthread_t a_thread;
void *thread_result;
res = pthread_create(&a_thread, NULL, thread_function, (void *)message);
Вы передаете адрес объекта типа pthread_t
, который можете применять в дальнейшем для ссылки на поток. Вы не хотите менять атрибуты потока, заданные по умолчанию, поэтому во втором параметре передаете NULL
. Последние два параметра — вызываемая функция и передаваемый ей параметр.
Если вызов завершился нормально, теперь выполняются два потока. Исходный поток ( main
) продолжается и выполняет код, расположенный следом за функцией pthread_create
, а новый поток начинает выполнение в функции, образно названной thread_function
.
Исходный поток проверяет, запустился ли новый поток, и затем вызывает функцию pthread_join
:
res = pthread_join(a_thread, &thread_result);
Здесь вы передаете идентификатор потока, который ждете, чтобы присоединить, и указатель на результат. Эта функция, прежде чем вернуть управление, будет ждать, пока другой поток не завершится. Затем она выводит возвращаемое из потока значение и содержимое переменной и завершается.
Новый поток начинает выполнение, запуская функцию thread_function
, которая выводит свои аргументы, засыпает на короткий период, обновляет глобальные переменные и затем завершается, возвращая строку в поток main
. Новый поток пишет в тот же массив message
, к которому у исходного потока есть доступ. Если бы вы вызвали функцию fork
вместо pthread_create
, массив представлял бы собой копию массива message
, а не сам массив.
Одновременное выполнение
В упражнении 12.2 показано, как написать программу, которая проверяет одновременное выполнение двух потоков. (Вы, конечно, применяете однопроцессорную систему, ЦП будет искусно переключаться между потоками, а не одновременно выполнять оба потока, используя отдельные ядра процессора аппаратными средствами.) Поскольку вы не встречались еще с какими-либо функциями синхронизации потоков, это будет очень неэффективная программа, делающая нечто, именуемое опросом (polling) двух потоков. И снова вы воспользуетесь тем, что все, за исключением локальных переменных функции, совместно используется двумя потоками в процессе.
Программа thread2.c в этом упражнении создается за счет небольших изменений программы thread1.c. Вы добавите дополнительную глобальную переменную для определения выполняющегося потока.
Файлы с полными текстами примеров можно загрузить с Web-сайта книги.
int run_now = 1;
Задайте run_now
равной 1, когда выполняется функция main
, и 2, когда выполняется новый поток.
В функцию main
после создания нового потока добавьте следующий код:
int print_count1 = 0;
while (print_count1+ < 20) {
if (run_now == 1) {
printf("1");
run_now = 2;
} else {
sleep(1);
}
}
Если переменная run_now
равна 1, выведите "1" и присвойте переменной значение 2. В противном случае вы на короткое время засыпаете и снова проверяете значение. Вы ждете, пока значение изменится на 1, проверяя время от времени снова. Этот прием называется циклам активного или деятельного ожидания (busy wait), несмотря, на то, что в данном случае программа засыпает на секунду между очередными проверками. Позже в этой главе вы увидите, как сделать это лучше.
В функции thread_function
, где выполняется ваш новый поток, вы делаете примерно то же самое, но с противоположными значениями.
int print_count2 = 0;
while (print_count2++ < 20) {
if (run_now == 2) {
printf("2");
run_now = 1;
} else {
sleep(1);
}
}
Вы удаляете переданные параметр и возвращаемое значение, т.к. они вас больше не интересуют.
Когда вы выполните программу, то увидите следующий вывод. (Вы можете обнаружить, что для формирования вывода, особенно на машине с одноядерным ЦП, программе потребуется несколько секунд.)
$ cc -D_REENTRANT thread2.с -о thread2 -lpthread
$ ./thread2
12121212121212121212
Waiting for thread to finish...
Thread joined
Как это работает
Каждый поток заставляет другой поток выполняться, задавая переменную run_now
и затем ожидая, пока другой поток не изменит значение, чтобы можно было продолжить выполнение. Из программы видно, что выполнение переходит от одного потока к другому автоматическими кроме того, она демонстрирует точку, совместно используемую обоими потоками, — переменную run_now
.
Синхронизация
В предыдущем разделе вы видели, что два потока выполняются одновременно, но метод переключения между ними топорный и очень неэффективный. К счастью, существует ряд функций, специально разработанных для предоставления лучших способов управления исполнением потоков и доступа к важным фрагментам кода.
В этом разделе мы рассмотрим два основных метода: семафоры, действующие как сторожа, охраняющие фрагменты кода, и мьютексы или исключающие семафоры, действующие как устройство взаимного исключения (отсюда и имя — исключающий семафор) для защиты фрагментов программного кода. На самом деле эти методы похожи, и один может быть описан в терминах другого. Тем не менее существуют ситуации, в которых семантика проблемы делает один более выразительным, чем другой. Например, управление доступом к некоторой области совместно используемой памяти, к которой может обращаться только один поток в каждый момент времени, более естественным кажется исключающий семафор или мьютекс. Для управления доступом к ряду идентичных объектов в целом, например, предоставление потоку одной телефонной линии из набора, включающего пять доступных линий, больше подходит семафор. Какой метод выберите вы, зависит от личных предпочтений и наиболее подходящего для вашей программы алгоритма.
Синхронизация с помощью семафоров
Для семафоров есть два набора интерфейсных функций: один взят из POSIX Realtime Extensions (дополнения POSIX для режима реального времени) и применяется для потоков, а другой, известный как семафоры System V, обычно применяется для синхронизации процессов. (Мы обсудим второй тип в главе 14.) Оба набора не гарантируют взаимозаменяемости и хотя очень похожи, используют вызовы разных функций.
Читать дальшеИнтервал:
Закладка: