I'm making a different version of my guessing game. This time, the child process has to send it's guess to the parent, which then evaluates that. What I think I'm doing wrong is that my child only runs once, but can't figure out how to get guesses until it finds the correct number.
#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 KEY 19950914
#define FLAG 0666
struct message {
long mtype;
int szam;
};
int main()
{
int number, false=1, guess=0;
int mqid;
struct message buf;
struct msqid_ds statbuff;
mqid = msgget(KEY, FLAG | IPC_CREAT);
if (mqid < 0)
perror("msgget"), exit(EXIT_FAILURE);
srand(time(NULL));
number = rand() % 256;
if (fork() == 0)
{
srand(time(NULL));
buf.mtype = 2;
buf.szam = rand() % 256;
msgsnd(mqid, &buf, sizeof(struct message), 0);
msgctl(mqid, IPC_STAT, &statbuff);
exit(EXIT_SUCCESS);
}
while ( guess != number )
{
if (guess > number)
printf("Too high!\n");
else if (guess < number)
printf("Too low!\n");
guess = msgrcv(mqid, &buf, sizeof(struct message), 2, 0);
}
printf("Winner! Yes, the answer was %d \n",number);
wait(NULL);
exit(EXIT_SUCCESS);
}
One way is to put the child in a loop, and then delete the message queue once you get the right answer, which will make
msgsndfail withEIDRMto exit the loop:I fixed a few other things in your program too:
KEY, I changed it toIPC_PRIVATE, which avoids the possibility of a key collision. Since you aren't trying to open the same queue elsewhere, there's no reason to use a fixed one.statbuffand yourIPC_STATcall. They weren't doing anything useful.srand. By doing two so close together,time(NULL)was the same both times, so your child program would have the same random number state, and so would end up guessing right on its first try every time.msgrcvis the size of the message, which will always be the same (probably 16). I changed it to check the actual guess, inbuf.szam.guesswas before your firstmsgrcv, which resulted in a spurious guess that wasn't from the child. I changed yourwhileloop to ado-whileloop to avoid this.And here's some more things that should be fixed, but that I leave as exercises for the reader:
false(a horrible name for a variable, by the way)perror("msgget"), exit(EXIT_FAILURE);. Just use braces and a semicolon.fork()to a variable, so you can check if it's negative, which would indicate failure.msgsndandmsgrcvis supposed to be the size of the second member of the message struct (i.e., not includingmtypeor the padding right after it), not the size of the whole struct.msgrcvto make sure it doesn't fail.ipcrm.)