Pull to refresh

Comments 22

Сейчас вспомнил, когда сдавал экзамен, мне задали вопрос: «Представим, что между двумя парами процессов инициализированы pipe и fifo соответственно. Какое может возникнуть отличие в их работе, если они взаимодействуют одинаково?»
На вопрос не ответил, а когда ушел, забыл спросить ответ. Может, кто-нибудь знает ответ на этот вопрос?
У pipe нет имени и он создается для единичного использования. Пайп создается в рамках одного процесса и pipe могут использовать только наследники этого процесса. Самый простой пример — «cat some_file | grep some_name». Здесь пайп создается шеллом, в котором запущена команда.
В отличие от pipe, fifo создается именованным и выглядит как обычный файл в системе Linux, с некоторыми оговорками. Доступ к fifo могут иметь кто угодно, кто имеет соответствующие привилегии.
Вот пример fifo:
prwxr-x--x 1 serge users 0 Jun 18 13:43 my_named_pipe
Нет, это я знаю, вопрос был в предположении, что и pipe и fifo уже были корректно созданы и открыты.
Разница такая: время жизни pipe не превышает время жизни породившего его процесса.
fifo — его еще называют именованным каналом. FIFO нужно удалять при необходимости, т. к. цикл его существования не привязан к времени жизни процесса.
Но отличие вызова shm_open() в том, что память будет оставаться выделенной до момента удаления или перезагрузки компьютера.)

Системному администратору, который работает с приложениями, которые используют shared memory и семафоры для IPC будет полезно знать пару команд: ipcs, ipcrm. Первой можно посмотреть эти объекты, второй — удалить.
В Linux shm_open() тупо открывает файл в /dev/shm, следовательно ls. Кстати чтобы избежать утечки ресурсов при работе с memmory mapped files, дескрипторы можно закрывать, а на файлы делать unlink как только сделали маппинг — на файлы есть счётчик ссылок. Заметил, что некоторые вообще дескриптор на замапленный файл передают через unix socket, чтобы unlink можно было сделать сразу же после open.
Эх, почему-то всегда интересные статьи по программированию появляются уже после экзамена =) все равно спасибо, продолжайте дальше!
А с чем связано, что имя семафора должно начинаться со слеша?
Сходу могу только сказать, что необходимость слеша в начале имени семафора продиктована требованиями POSIX стандарта. Почему это так, я сейчас не могу сказать. Обещаю поискать больше информации по этому поводу и ответить на ваш вопрос.
Вобщем вот что я накопал для вашего вопроса:
1. Стандарт POSIX утверждает что если имя нашего семафора начинается со слеша, то любой вызов sem_open с таким именем в любой процедуре должен возвращать дескриптор одного и того же семафора. Проще говора вызов sem_open("/semaphore",...) в любой процедуре вернет дескриптор одного и того же семафора. Тот же стандарт пишет, что если слеша в начале имени нет, то поведение стандартом не описывается, а ложится на плечи разработчиков sem_open. Проще говоря, что делать с именем семафора без слеша в начале «решает» конретная реализация sem_open.
2. Я не поленился глянуть в реализацию sem_open в стандартной библиотеке glibc. Так вот тамошняя реализация функции допускает отсутствие слеша. Более того, sem_open не пользуется слешом в начале имени, а смело его пропускает вот таким наглым образом:
sem_t * sem_open (const char *name, int oflag, ...) {

/* Construct the filename. */
while (name[0] == '/')
++name;

3. Ответ на ваш вопрос: имя семафора должно начинаться со слеша, скорее всего, потому, что семафор, как и разделенная память, должен создаваться в файловой системе ОС. Выглядеть это должно примерно так: /dev/sem/my_semaphore_name. Именно так реализовано в системе QNX, которая, к слову сказать, является полностью POSIX совместимой, в отличие от Linux.
Тема про семафоры по-моему раскрыта не полно. А вообще, хорошо, спасибо.
Про d-bus почитаю с удовольствием.
Расписал чуть подробнее. Добавил подглаву про mutex.
Про DBus интересно было бы. Использовал его пару раз из Python и из консоли через qdbus, но не сильно вникал в подробности. В частности интересно — DBus где-то кроме десктопа актуален? Как у него с ограничением прав доступа?

А в статье хотелось бы еще видеть рекомендации что в каких случаях лучше применять…
а как связан описанный тут механизм shm с загрузкой so библиотек?
Библитеки также мапятся через mmap (c PROT_READ|PROT_EXEC и MAP_SHARED) так что механизм тот-же.
тоесть, ld-linux, окромя манипуляциями с таблицами ссылок, никакой особой подземной магии не юзает?
Не, ну там куча логики но в том что касается shared memory всё просто — open и mmap, а там уже ядру решать.
Хорошая статья, спасибо!
Давно хотел посмотреть про разделяемую память и тут на тебе. Спасибо.
Хочу кое-что заметить/спросить. В случае разделяемой памяти — зачем использовать mmap/memcpy, если можно просто работать с дескриптором? Я вот тут экспериментировал и оказалось, что можно просто вызывать read/write для такого дескриптора и всё будет отлично работать. Так вроде даже проще…
Последовательно действий именно такая:

1) идентифицировать разделяемую область неким символичным именем, к примеру "/mySharedMem"
2) с помощью shm_open открыть файловый дескриптор на только что идентифицированной области
3) ftruncate'ом задать необходимый размер сегмента
4) с помощью mmap мапировать этот сегмент в свое адресное пространство
Подскажите пожалуйста как отличить именованный канал от обычного файла?

Реализовал работу с каналами точно так же как в примере с mkfifo.c
Цитата кода из статьи
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>

#define NAMEDPIPE_NAME "/tmp/my_named_pipe"
#define BUFSIZE        50

int main (int argc, char ** argv) {
    int fd, len;
    char buf[BUFSIZE];

    if ( mkfifo(NAMEDPIPE_NAME, 0777) ) {
        perror("mkfifo");
        return 1;
    }
    printf("%s is created\n", NAMEDPIPE_NAME);

    if ( (fd = open(NAMEDPIPE_NAME, O_RDONLY)) <= 0 ) {
        perror("open");
        return 1;
    }
    printf("%s is opened\n", NAMEDPIPE_NAME);

    do {
        memset(buf, '\0', BUFSIZE);
        if ( (len = read(fd, buf, BUFSIZE-1)) <= 0 ) {
            perror("read");
            close(fd);
            remove(NAMEDPIPE_NAME);
            return 0;
        }
        printf("Incomming message (%d): %s\n", len, buf);
    } while ( 1 );
}



в итоге всё работает хорошо. Но если канал существует то он используется а не удаляется и создаётся заново. И тоже всё работает.
Но если вместо канала создан обычный файл то mkfifo не вернёт ошибку, а код чтения из этого файла будет выполнятся в бесконечном цикле без остановки.

Only those users with full accounts are able to leave comments. Log in, please.