Именованный канал С++ Linux зависает на open() с O_WRONLY

Это мой простой код, который открывает именованный канал, записывает в него строку, а затем закрывает канал. Канал создается в другой функции, как указано ниже.

char * ipcnm = "./jobqueue";

std::cout << "opening job queue" << std::endl;

//ensure the jobqueue is opened
if ((jobq = open(ipcnm, O_WRONLY)) < 0) {
  perror("open");
  exit(-1);
}

std::cout << "queue opened" << std::endl;

// record the number of bytes written to the queue
size_t written = write(jobq, ptr, size*nmemb);

// close fifo
if (close(jobq) < 0) {
  perror("close");
  exit(-1);
}

// need to report to other agents the size of the job that was written
jobSizes.push_back(written);

но вызов open() зависает. Я убедился, что нет другого процесса, использующего «очередь заданий» fifo во время вызова, а права доступа к файлу для очереди после ее создания установлены как prwxrwxr-x (я просто использую mkfifo(ipcnm, 0777) для создания канала.

Сначала я подумал, что проблема в том, что у группы o отсутствуют w разрешения на этот канал, поэтому я вручную изменил их с помощью chmod, и он все еще зависает, так как «очередь открыта» никогда не печатается. Так же как и сообщение об ошибке для perror("open");

Что мне не хватает?


person kjh    schedule 07.06.2014    source источник


Ответы (2)


Когда вы открываете FIFO для записи, писатель блокируется до тех пор, пока не появится читатель.

Вы, вероятно, скучаете по читателю.

Вы не можете написать в канал, затем закрыть его, а затем заставить читателя прийти позже. Такая семантика хранения достигается за счет использования обычного файла.

Каналы — это механизм межпроцессного взаимодействия; канал, созданный открытием FIFO, аналогичен объекту, возвращаемому библиотечной функцией pipe POSIX C, за исключением того, что pipe возвращает объект, который уже подготовлен для ввода-вывода, поскольку имеется два дескриптора: противоположные концы открыты для противоположных направлений ввода /О. В то время как конечные точки FIFO открываются отдельно по одной за раз.

Объект FIFO в файловой системе — это всего лишь точка контакта, которая позволяет нескольким процессам подключаться к одному и тому же каналу.

Изначально объекта трубы не существует. Когда первый процесс выполняет open для объекта FIFO в файловой системе, создается канал. Любые дополнительные запросы open от того же или другого процесса присоединяются к тому же объекту канала, хранящемуся в ядре. Ввод-вывод не может иметь место, пока канал не будет открыт хотя бы один раз для чтения и хотя бы один раз для записи. Фактический ввод-вывод канала проходит через ядро; он не хранится в файловой системе. Когда все процессы закрывают канал, объект исчезает.

FIFO можно спроектировать таким образом, чтобы ввод-вывод мог начаться до того, как какой-либо процесс откроет объект для чтения. Другими словами, запрос на запись может быть разрешен, а затем заблокирован только тогда, когда канал заполнится. У этой конструкции были бы проблемы. Например, что делать, если запись маленькая, чтобы труба не заполнялась? Писатель запишет данные и продолжит их выполнение. Если он просто выйдет до того, как читатель прочитает данные, данные исчезнут навсегда! Поведение блокировки гарантирует, что читатель сможет перехватить данные; когда модуль записи разблокирован, он может быть уверен, что канал чтения открыт, и поэтому он может безопасно закрыть свой конец канала без потери данных. Дизайн, который не блокирует запись, даже если читатель недоступен, должен будет держать объект канала внутри ядра, даже если он не открыт ни одним процессом, чтобы писатель мог открыть канал, поместить в него данные, а затем уйти. и позже читатель может подобрать данные. В противном случае дизайн должен был бы предоставить писателю блокировку close (аналогично SO_LINGER-устроенному поведению на сокете), которая ожидает удаления ранее записанных данных.

person Kaz    schedule 07.06.2014
comment
ах, я ошибочно думал, что программа будет блокироваться только до тех пор, пока не появится писатель, если вы откроете ее в режиме только для чтения. Я не знал, что писатель также будет ждать читателя. Большое спасибо - person kjh; 07.06.2014
comment
@Kaz, можете ли вы объяснить, почему это условие необходимо? - person sonus21; 17.01.2015
comment
@sonukumar: в этом нет необходимости; это просто есть. Вот что делают трубы. Используйте файлы, если вам не нужны каналы. - person Lightness Races in Orbit; 17.01.2016
comment
@LightnessRacesinOrbit Спасибо, но я хотел бы знать причины этого. - person sonus21; 19.01.2016
comment
@sonukumar: Как вы думаете, почему есть конкретное рассуждение? Это естественное следствие того, что такое трубы. Это все равно, что спрашивать, в чем причина того, что только четыре человека могут сидеть в четырехместной машине. Никто не решил, что на одно место должен приходиться один человек — это естественное следствие того, что такое места. На самом деле лучшей аналогией было бы то, что когда вы звоните кому-то по телефону, вы блокируете прослушивание этого звонка, пока человек на другом конце не возьмет трубку; вы не можете начать говорить с ними, пока они не взяли трубку. Опять же, никто не решил, что так должно быть - это естественно. - person Lightness Races in Orbit; 19.01.2016
comment
@sonukumar Я добавил к ответу текст, чтобы попытаться решить, почему. - person Kaz; 19.01.2016
comment
@LightnessRacesinOrbit Тем не менее, я расширил ответ, чтобы объяснить, почему это происходит. - person Kaz; 19.01.2016
comment
@Kaz Спасибо, это выглядит более многообещающе. - person sonus21; 19.01.2016
comment
@LightnessRacesinOrbit Я исправил дезинформацию в этом ответе. - person Kaz; 12.05.2016

Используйте O_RDWR вместо O_WRONLY для открытия. Это откроет fifo без блокировки, даже если считыватель еще не открыт на другом конце.

person Viatcheslav Alekseev    schedule 02.03.2018