Один из способов - поместить ребенка в al oop, а затем удалить очередь сообщений, как только вы получите правильный ответ, что приведет к сбою msgsnd
при EIDRM
для выхода из l oop:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <sys/wait.h>
#include <time.h>
#define FLAG 0666
struct message {
long mtype;
int szam;
};
int main()
{
int number, false=1, guess;
int mqid;
struct message buf;
mqid = msgget(IPC_PRIVATE, FLAG | IPC_CREAT);
if (mqid < 0)
perror("msgget"), exit(EXIT_FAILURE);
srand(time(NULL));
number = rand() % 256;
if (fork() == 0)
{
buf.mtype = 2;
int sndres;
do {
buf.szam = rand() % 256;
sndres = msgsnd(mqid, &buf, sizeof(struct message), 0);
} while(sndres == 0);
exit(EXIT_SUCCESS);
}
do {
msgrcv(mqid, &buf, sizeof(struct message), 2, 0);
guess = buf.szam;
if (guess > number)
printf("Too high!\n");
else if (guess < number)
printf("Too low!\n");
} while ( guess != number );
printf("Winner! Yes, the answer was %d \n",number);
msgctl(mqid, IPC_RMID, NULL);
wait(NULL);
exit(EXIT_SUCCESS);
}
Я также исправил несколько других вещей в вашей программе:
- Вместо того, чтобы использовать фиксированный
KEY
, я изменил его на IPC_PRIVATE
, что исключает возможность столкновение клавиш. Поскольку вы не пытаетесь открыть ту же очередь в другом месте, нет причин использовать фиксированную. - Я избавился от
statbuff
и вашего IPC_STAT
вызова. Они не делали ничего полезного. - Я удалил ваш второй звонок на
srand
. Делая два так близко друг к другу, time(NULL)
был одинаковым оба раза, поэтому ваша дочерняя программа будет иметь одно и то же состояние случайных чисел, и в результате каждый раз будет угадываться с первой попытки. - Return значение успешного
msgrcv
- это размер сообщения, который всегда будет одинаковым (вероятно, 16). Я изменил его, чтобы проверить фактическое предположение, в buf.szam
. - Ваша первая проверка
guess
была до вашей первой msgrcv
, что привело к ложному предположению, которое было не от ребенка. Я изменил ваш while
l oop на do-while
l oop, чтобы избежать этого.
И вот еще несколько вещей, которые следует исправить, но я оставляю их в качестве упражнений для читатель:
- Избавьтесь от всего, что вы на самом деле не используете, например
false
(кстати, ужасное имя переменной) - Не будь таким " умный "с запятыми, как в
perror("msgget"), exit(EXIT_FAILURE);
. Просто используйте фигурные скобки и точку с запятой. - Вы должны сохранить результат
fork()
в переменной, чтобы вы могли проверить, отрицательный ли он, что будет указывать на ошибку. - Размер, который вы передаете
msgsnd
и msgrcv
должны быть размером второго элемента структуры сообщения (т. Е. Не включая mtype
или заполнение сразу после него), а не размером всей структуры. - Вы должны проверить возврат
msgrcv
, чтобы убедиться, что он не потерпит неудачу. - Запуск потомка с постоянной l oop, как я это сделал, является самым простым подходом, но не обязательно самым эффективным или Лучший. Подумайте о том, чтобы родитель отправлял сообщения дочернему элементу, чтобы он выдавал только одно предположение за раз вместо заполнения очереди настолько, насколько это возможно. (Даже если вы сделаете это изменение, вы все равно должны позволить родителю удалить очередь сообщений в конце, потому что в противном случае она не исчезнет go, пока вы не перезагрузите или не очистите ее вручную с помощью
ipcrm
.)