我正在制作猜谜游戏的其他版本。这次,子进程必须将其猜测发送给父进程,然后由父进程对其进行评估。我认为我做错了,是我的孩子只跑了一次,但直到找到正确的数字,才弄清楚如何猜测。
#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);
}
一种方法是将子级置于循环中,然后在获得正确答案后删除消息队列,这将使msgsnd
失败,并导致EIDRM
退出循环:
#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)
两次都是相同的,因此您的子程序将具有相同的随机数状态,因此每次都将在第一次尝试时就猜对了。msgrcv
的返回值是消息的大小,该大小将始终相同(可能为16)。我在buf.szam
中更改了它以检查实际的猜测。guess
之前第一次检查msgrcv
,但添加了不是来自孩子的虚假猜测。为了避免这种情况,我将您的while
循环更改为do-while
循环。还有一些应该解决的问题,但我留给读者练习:
false
(顺便说一下,变量的可怕名称)perror("msgget"), exit(EXIT_FAILURE);
那样用逗号“巧妙地”。只需使用花括号和分号即可。fork()
的结果保存到变量中,以便可以检查它是否为负值,这将指示失败。msgsnd
和msgrcv
的大小应该是消息结构的第二个成员的大小(即,不包括mtype
),而不是整个结构的大小。msgrcv
的返回值以确保它不会失败。ipcrm
手动将其清除,否则消息队列不会消失。)