Вход/Регистрация
Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform
вернуться

Кёртен Роб

Шрифт:

При использовании составных сообщений в QNX/Neutrino непосредственно клиентским вызовом chown создается одиночное сообщение, выглядящее примерно так:

Составное сообщение.

Сообщение состоит из двух частей. Первая часть посвящена установлению соединения (подобно сообщению, которое сгенерировала бы функция open), вторая — вводу/выводу (эквивалент сообщения, генерируемого функцией fchown). Никакого эквивалента функции close здесь нет, поскольку мы выбрали сообщение типа _IO_CONNECT_COMBINE_CLOSE, которое гласит: «Открой указанное имя пути, используй полученный дескриптор файла для обработки остальной части сообщения, а когда закончишь дела или столкнешься с ошибкой, закрой дескриптор».

Написанный вами администратор ресурса даже не заметит, вызвал ли клиент функцию chown или сначала сделал open, а потом вызвал fchown и далее close. Все это скрыто базовым уровнем библиотеки.

Составные сообщения

Как выясняется, концепция составных сообщений полезна не только для экономии ресурсов вследствие уменьшения числа сообщений (как в случае с chown, см. выше). Она также критически важна для обеспечения атомарности операций.

Предположим, что в клиентском процессе есть два или более потоков, работающих с одним дескриптором файла. Один из потоков в клиенте вызывает функцию lseek, за которой следует read. Все так, как мы и предполагаем. А вот если другой клиента попробует выполнить ту же самую последовательность операций с тем же самым дескриптором файла, вот тут у нас начнутся проблемы. Поскольку функции lseek и read друг о друге ничего не знают, то возможно, например, что первый поток выполнит lseek, а затем будет вытеснен вторым потоком. Второй поток выполнит свои lseek и read, после чего освободит процессор. Проблема здесь состоит в том, что поскольку эти два потока разделяют один и тот же дескриптор файла, у первого потока теперь получается неправильное смещение lseek, поскольку оно было изменено функциями lseek и read второго потока! Эта проблема проявляется также с дескрипторами файлов, которые дублируются (dup) между процессами, не говоря уже о сети.

Очевидным решением здесь является заключение lseek и read в пределы действия мутекса — когда первый поток захватит мутекс, мы будем знать, что он имеет эксклюзивный доступ к дескриптору. Второй поток должен будет ждать освобождения мутекса, прежде чем он сможет творить свое безобразие с позиционированием дескриптора.

К сожалению, если кто-то вдруг забудет захватить мутекс перед каждой и любой операцией с дескриптором файла, всегда остается возможность того, что такой «незащищенный» доступ может привести поток к чтению или записи данных не туда, куда надо.

Давайте взглянем на библиотечный вызов readblock (из

<unistd.h>
):

int readblock(int fd, size_t blksize, unsigned block,

 int numblks, void *buff);

(Функция writeblock описывается аналогично.)

Вы можете вообразить для функции readblock довольно «простенькую» реализацию:

int readblock(int fd, size_t blksize, unsigned block,

 int numblks, void *buff) {

 lseek(fd, blksize * block, SEEK_SET); // Идем к блоку

 read(fd, buff, blksize * numblks);

}

Очевидно, что от такой реализации в многопоточной среде толку мало. Нам нужно будет как минимум добавить использование мутекса:

int readblock(int fd, size_t blksize, unsigned block,

 int numblks, void *buff) {

 pthread_mutex_lock(&block_mutex);

 lseek(fd, blksize * block, SEEK_SET); // Идем к блоку

 read(fd, buff, blksize * numblks);

 pthread_mutex_unlock(&block_mutex);

}

(Мы здесь предполагаем, что мутекс уже инициализирован.)

Этот код по-прежнему уязвим для «незащищенного» доступа — если некий поток вызовет lseek на этом файловом дескрипторе без предварительной попытки захвата мутекса, вот у нас уже и ошибка.

Решение проблемы заключается в использовании составного сообщения, аналогично вышеописанному случаю с функцией chown. В данном случае библиотечная реализация функции readblock помещает обе операции — lseek и read — в единое сообщение и посылает это сообщение администратору ресурсов:

Составное сообщение для функции readblock.

Это работает, потому что передача сообщения является атомарной операцией. С точки зрения клиента, сообщение уходит либо целиком, либо не уходит вообще. Поэтому, вмешательство «незащищенной» функции lseek становится несущественным — когда администратор ресурсов принимает сообщение с запросом readblock, он делает это за один прием. (Очевидно, что в этом случае пострадает сама «незащищенная» lseek, поскольку после отработки readblock смещение на этом дескрипторе файла будет отличаться от того, которое она хотела установить.)

  • Читать дальше
  • 1
  • ...
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: