Есть ли способ отправить EOF процессу, читающему очередь сообщений?

У меня есть один процесс отправки данных через очередь сообщений с msgsnd, Еще один процесс чтения из очереди с msgrcv, Процесс чтения должен ждать, пока у него не появятся все сообщения, прежде чем он сможет продолжить. Как я могу сказать, что все сообщения были отправлены?

То, как я это делал, - после того, как отправитель отправил все свои сообщения, он затем проверяет количество сообщений в очереди в цикле while. Когда больше нет сообщений, он закрывает очередь.

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

Есть ли способ для меня просто отправить сообщение EOF и следить за процессом чтения? Тогда я мог бы просто отправить EOF и завершить процесс отправки.

1 ответ

Обычно получатель замечает, что отправитель закончил отправку, потому что он пытается получить следующее сообщение, а приемный вызов указывает, что для получения ничего не осталось. При связи через файловые дескрипторы (каналы, сокеты) закрытие - это то, как вы "отправляете EOF", и read вызов возвращает 0 байтов. С очередями сообщений это немного отличается, потому что они основаны на сообщениях, а не на потоках, и часто бывает несколько отправителей.

Ты можешь позвонить msgctl с командой IPC_RMID, Это вызывает любое ожидание или последующий вызов msgrcv (или же msgsnd) возвращать -EIDRM (-EINVAL на некоторых системах BSD). Проблема с этим подходом состоит в том, что в очереди могут быть сообщения, ожидающие в очереди, которые получатель еще не прочитал, и поэтому мы потерялись.

Вместо этого, когда отправителю больше нечего делать, отправьте в очередь сообщение с надписью "Я закончил". В получателе, когда вы получите это сообщение, удалите очередь. Это хорошо работает, когда вы используете очередь между потоками одного процесса. Если существует несколько процессов, отправитель может умереть, не отправив сообщение о завершении.

То, как обрабатывать случай с несколькими процессами, будет зависеть от структуры вашего приложения и, в частности, от того, что процесс чтения хочет сделать, когда отправитель мертв. Один из способов обнаружить это - установить канал между отправителем и получателем. Пусть поток на ресивере прослушивает этот канал; если он обнаруживает конец файла, он может

  1. установить переменную, которая используется совместно с потоком, который вызывает msgrcv;
  2. заглянуть в очередь (msgctl с IPC_STAT);
  3. если очередь пуста (msg_qnum == 0), убери это.
Другие вопросы по тегам