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 msgsnd
fail with EIDRM
to exit the loop:
#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);
}
I fixed a few other things in your program too:
KEY
, I changed it to IPC_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.statbuff
and your IPC_STAT
call. 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.msgrcv
is the size of the message, which will always be the same (probably 16). I changed it to check the actual guess, in buf.szam
.guess
was before your first msgrcv
, which resulted in a spurious guess that wasn't from the child. I changed your while
loop to a do-while
loop 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.msgsnd
and msgrcv
is supposed to be the size of the second member of the message struct (i.e., not including mtype
or the padding right after it), not the size of the whole struct.msgrcv
to make sure it doesn't fail.ipcrm
.)