Как закрыть/очистить очередь сообщений IPC?

#c #ipc #message-queue

Вопрос:

У меня есть этот вызов при очистке основного потока process_B, который получает сообщения в очереди сообщений IPC:

 if (msgctl(qId, IPC_RMID, NULL) < 0) {
    perror("msgctl");
}
 

И когда достигнуто, сообщает следующее:

 msgctl : Invalid argument
Error: failed to remove message queue.
 

У меня есть другой process_A, который отправляет сообщения в process_B и не завершается.

Затем есть это заявление man msgctl

     IPC_RMID
              Immediately remove the  message  queue,  awakening  all  waiting
              reader  and writer processes (with an error return and errno set
              to EIDRM).  The calling process must have appropriate privileges
              or  its  effective user ID must be either that of the creator or
              owner of the message queue.  The third argument to  msgctl()  is
              ignored in this case.
 

Я не совсем понимаю, как удаление очереди сообщений пробуждает всех читателей и авторов. Должен ли process_A каким-то образом закрыться, прежде чем process_B сможет удалить очередь сообщений?

Если process_B закроется, я пытаюсь очистить ресурсы, чтобы включить эту очередь сообщений. И если он перезапущен, я бы хотел, чтобы process_B «повторно подключился» к очереди сообщений после очистки очереди в случае, если process_A никогда не был выключен. Возможна ли очистка очереди? И тогда, конечно, я бы сделал то же самое для process_A.

Обновление: (добавление открытия очереди сообщений):

     key_t key = ftok(".", 'm');

    int qid = msgget(key, IPC_CREAT | 0644);
    
    if (qid == -1) {
        perror("msgget");

        return -1;
    }
 

Комментарии:

1. Можете ли вы показать, как вы открыли свою очередь сообщений?

2. Добавлено открытие. Отправка сообщений между двумя процессами проходит успешно.

3. Находится qid в области, куда вы звоните (msgctl(qId, IPC_RMID, NULL) ?

Ответ №1:

У меня есть этот вызов при очистке основного потока process_B, который получает сообщения в очереди сообщений IPC:

 if (msgctl(qId, IPC_RMID, NULL) < 0) {
    perror("msgctl");
}
 

И когда достигнуто, сообщает следующее:

 msgctl : Invalid argument
Error: failed to remove message queue.
 

Сообщение «Ошибка:» должно быть из какого-то другого кода, которого нет , но сообщение «msgctl:», по-видимому, выводится из сообщения perror() , сообщающего об EINVAL ошибке . Для IPC_RMID команды это указывает на то, что идентификатор очереди, переданный функции, был недопустимым. Возможно, эта очередь уже была удалена?

Я не совсем понимаю, как удаление очереди сообщений пробуждает всех читателей и авторов. Должен ли process_A каким-то образом закрыться, прежде чем process_B сможет удалить очередь сообщений?

Удаление очереди пробуждает всех ожидающих читателей и авторов. То есть те, которые в данный момент заблокированы, пытаются отправлять сообщения в очередь или получать из нее сообщения. В документах просто говорится, что эти вызовы перестанут блокироваться, и вместо этого произойдет сбой (возврат -1) с errno установленным значением EIDRM . Так что нет, process_A не должен завершать или выполнять какие-либо другие действия, прежде чем process_B сможет удалить очередь.

однако,

Если process_B закроется, я пытаюсь очистить ресурсы, чтобы включить эту очередь сообщений.

Пока все в порядке.

И если он перезапущен, я бы хотел, чтобы process_B «повторно подключился» к очереди сообщений после очистки очереди в случае, если process_A никогда не был выключен.

Я думаю, вы не понимаете, что значит удалить очередь. После успешного удаления его больше не к чему подключаться. Вместо этого вы должны создать новую очередь и каким-то образом подключить все задействованные процессы к этой очереди и использовать ее. У него вполне может быть другой идентификатор очереди (хотя и полученный с помощью того же ключа).

Возможна ли очистка очереди? И тогда, конечно, я бы сделал то же самое для process_A.

Вы можете очистить очередь, не удаляя ее, запретив всем процессам отправлять новые сообщения (через общий для процессов мьютекс или семафор), а затем получать все доступные сообщения. Не забудьте предусмотреть, чтобы мьютекс / семафор был выпущен.

Однако я настоятельно призываю вас подумать о своей стратегии здесь. Если вы просто очистите очередь, не удаляя ее, то ничто не помешает process_A отправлять больше сообщений в очередь, пока process_B не запущен, так что

  1. очистка очереди на самом деле не сильно влияет на использование ресурсов, и
  2. вам нужно подумать о том, что новый process_B будет делать с сообщениями, отправленными до начала выполнения.

То же самое относится и к обратному направлению.

Кроме того, помните, что очереди сообщений System V обладают сохраняемостью ядра, поэтому их срок службы не привязан к сроку службы какого-либо конкретного процесса. MQS SysV будут жить с момента их создания до их явного удаления или до тех пор, пока система не завершит работу, в зависимости от того, что произойдет раньше.