Основи програмування в Linux

У четвертому виданні популярного керівництва надано основи програмування в операційній системі Linux. Розглянуті: використання бібліотек C/C++ та стандартних засобів розробки, організація системних викликів, файлове введення/виведення, взаємодія процесів, програмування засобами командної оболонки, створення графічних інтерфейсів за допомогою інструментальних засобів GTK+ або Qt, застосування сокетів та ін. Описана компіляція програм, їх компонування з бібліотеками та робота з термінальним введенням/виводом. Наведено прийоми написання додатків у середовищах GNOME® та KDE®, зберігання даних з використанням СУБД MySQL® та налагодження програм. Книга добре структурована, що робить навчання легким та швидким.
Для Linux-програмістів-початківців
Основи програмування в Linux
Розділи на цій сторінці:
Дуже часто при розробці додатків Linux вам може знадобитися перевірка стану ряду вводів для того, щоб визначити наступну дію. Наприклад, програма обміну даними, така як емулятор термінала, потребує ефективного способу одночасного читання з клавіатури та з послідовного порту. В однокористувацькій системі підійде цикл "активного очікування", що багаторазово переглядає введення в пошуку даних і читає їх, як тільки вони з'являться. Така поведінка дуже марнотратна щодо часу ЦП.
Системний виклик select дозволяє програмі чекати на прибуття даних (або завершення виведення) одночасно на декількох низькорівневих файлових дескрипторах. Це означає, що програма емулятора терміналу може блокуватися доти, доки у неї не з'явиться робота. Аналогічно сервер може мати справу з численними клієнтами, чекаючи запити одночасно на багатьох відкритихсокетів.
Функція select оперує структурами даних fd_set , що є безліччю відкритих файлових дескрипторів. Для обробки цих множин визначено набір макросів:
#include #includevoid FD_ZERO(fd_set *fdset);void FD_CLR(int fd, fd_set *fdset);void FD_SET(int fd, fd_set *fdset);int FD_ISSET(int fd, fd_set *fdset);
Як і передбачається відповідно до їх імен, макрос FD_ZERO ініціалізує структуру fd_set порожньою множиною, FD_SET і FD_CLR задають і очищають елементи множини, відповідного файловому дескриптору, переданому як параметр fd , а макрос FD_ISSET повертається є елементом структури fd_set , на яку вказує параметр fdset . Максимальна кількість файлових дескрипторів у структурі типу fd_set визначається константою FD_SETDIZE .
Функція select може також використовувати значення для часу очікування, щоб запобігти безкінечному блокуванню. Це значення задається за допомогою структури struct timeval. Вона визначена у файлі sys/time.h і містить такі елементи:
struct timevaltime_t tv_sec; /* Секунди */long tv_usec; /* Мікросекунди */>
Тип time_t, визначений у файлі sys/types.h, - цілісний. Системний виклик select оголошується так:
#include#includeint select(int nfds, fd_set *readfds, fd_set *writefds,fd_set * errorfds, struct timeval *timeout);
Виклик select дозволяє перевірити, чи не готовий хоча б один із множини файлових дескрипторів до читання чи запису, чи перебуває в очікуванні через стан помилки і може бути заблокований до моменту готовностіодного з дескрипторів.
Аргумент nfds задає кількість файлових дескрипторів, що перевіряються, маються на увазі дескриптори від 0 до nfds-1 . Кожна з трьох множин дескрипторів може виявитися порожнім покажчиком, тоді пов'язаний з ним тест не виконується.
Функція select поверне керування, якщо який-небудь з дескрипторів у множині readfds готовий до читання, який-небудь дескриптор з множини writefds готовий до запису або в одного з дескрипторів множини errorfd є стан помилки. Якщо жодної з умов не дотримується, select поверне керування після проміжку часу, заданого timeout . Якщо параметр timeout — порожній вказівник і немає активності на сокетах, виклик може бути заблокований на невизначений час.
Коли select повертає керування програмою, безліч дескрипторів буде модифіковано для того, щоб вказати на готові до читання або запису або помилки, що мають дескриптори. Для перевірки слід використовувати макрос FD_ISSET , що дозволяє визначити, які дескриптори вимагають уваги. Можна змінити значення timeout, щоб показати час, що залишається до наступного перевищення часу очікування, але така поведінка не задано стандартом X/Open. При перевищенні часу очікування всі дескриптори будуть очищені.
Виклик select повертає загальну кількість дескрипторів у модифікованих множинах. У разі збою він поверне -1 і встановить змінну errno , що описує помилку. Можливі помилки – EBADF для невірних дескрипторів, EINTR для повернення через переривання та EINVAL для некоректних значень параметрів nfds або timeout.
Примітка
Незважаючи на те, що Linux модифікує структуру, на яку вказує timeout , фіксуючи невикористаний час, що залишився, більшість версій UNIX цього не роблять.Більшість існуючого програмного коду, що застосовує функцію select , ініціалізує структуру типу timeval і потім продовжує використовувати її без оновлення вмісту. У системі Linux цей код може виконуватися некоректно, оскільки Linux змінює структуру timeval при кожному закінченні відведеного часу очікування. Якщо ви пишете або переносите програмний код, який використовує функцію select , слід враховувати цю різницю та завжди повторно ініціалізувати час очікування. Майте на увазі, що обидва підходи коректні, вони просто різні!
Виконайте вправу 15.8.
Вправа 15.8. Функція select
Далі для демонстрації застосування функції select наведено програму select.c. Більш складний приклад ви побачите трохи згодом. Програма читає дані з клавіатури (стандартне введення – дескриптор 0) з часом очікування 2,5 секунди. Дані читаються лише тоді, коли введення готове. Природно розширити програму, увімкнувши залежно від характеру програми інші дескриптори, такі як послідовні канали (serial lines) та сокети.
#include #include #include #include #include #include #include int main() char buffer[128]; int result, nread; fd_set inputs, testfds; struct timeval timeout; FD_ZERO(&inputs); FD_SET(0, &inputs);
2. Зачекайте введення файлу stdin протягом максимум 2,5 секунд: