Linux 中的 IPC 机制完成“石头、剪刀、布”游戏的C语言代码
时间: 2024-05-14 09:18:28 浏览: 182
好的,以下是一个简单的使用Linux中的进程间通信(IPC)机制来完成石头、剪刀、布游戏的C语言代码示例:
```c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define SHM_SIZE 1024 // 共享内存大小
// 定义信号灯的PV操作
void P(int semid);
void V(int semid);
int main(int argc, char *argv[]) {
int shmid, semid, *shm_ptr;
key_t key;
int player1_choice = -1, player2_choice = -1; // 玩家1和玩家2选择(0为石头,1为剪刀,2为布)
int rand_num; // 产生的随机数
int win, lose, tie; // 统计胜负平局次数
pid_t pid;
// 生成共享内存和信号灯的key值
if ((key = ftok(".", 'm')) == -1) {
perror("ftok error");
exit(1);
}
// 创建共享内存段
if ((shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0666)) < 0) {
perror("shmget error");
exit(1);
}
// 连接共享内存并获得指向共享内存的指针
if ((shm_ptr = shmat(shmid, 0, 0)) == (int *) -1) {
perror("shmat error");
exit(1);
}
// 创建一个二元信号量
if ((semid = semget(key, 1, IPC_CREAT | 0666)) == -1) {
perror("semget error");
exit(1);
}
// 初始化信号量的值为1
semctl(semid, 0, SETVAL, 1);
// 玩家1进程
if ((pid = fork()) < 0) {
perror("fork error");
exit(1);
} else if (pid == 0) {
srand(time(NULL)); // 初始化随机数种子
while (1) {
printf("请输入 0(石头)、1(剪刀)或 2(布),输入q退出:\n");
scanf("%d", &player1_choice);
getchar(); // 消耗回车符
// 如果输入的是q,则退出循环
if (player1_choice == 'q') {
break;
}
// 控制用户输入有效的选项
if (player1_choice < 0 || player1_choice > 2) {
printf("无效的选项,请重新输入!\n");
continue;
}
// 等待另一玩家完成选择
P(semid);
// 从共享内存中读取另一玩家的选择
player2_choice = *shm_ptr;
// 判断胜负并输出结果
if ((player1_choice == 0 && player2_choice == 1) ||
(player1_choice == 1 && player2_choice == 2) ||
(player1_choice == 2 && player2_choice == 0)) {
printf("\n您出的是 %d(%s),另一个玩家出的是 %d(%s),您赢了!\n",
player1_choice, (player1_choice == 0 ? "石头" : player1_choice == 1 ? "剪刀" : "布"),
player2_choice, (player2_choice == 0 ? "石头" : player2_choice == 1 ? "剪刀" : "布"));
win++;
} else if ((player2_choice == 0 && player1_choice == 1) ||
(player2_choice == 1 && player1_choice == 2) ||
(player2_choice == 2 && player1_choice == 0)) {
printf("\n您出的是 %d(%s),另一个玩家出的是 %d(%s),您输了!\n",
player1_choice, (player1_choice == 0 ? "石头" : player1_choice == 1 ? "剪刀" : "布"),
player2_choice, (player2_choice == 0 ? "石头" : player2_choice == 1 ? "剪刀" : "布"));
lose++;
} else {
printf("\n您出的是 %d(%s),另一个玩家出的是 %d(%s),平局!\n",
player1_choice, (player1_choice == 0 ? "石头" : player1_choice == 1 ? "剪刀" : "布"),
player2_choice, (player2_choice == 0 ? "石头" : player2_choice == 1 ? "剪刀" : "布"));
tie++;
}
// 释放信号灯
V(semid);
}
printf("您获胜 %d 次,失败 %d 次,平局 %d 次。\n", win, lose, tie);
printf("游戏结束!\n");
exit(0);
}
// 玩家2进程
if ((pid = fork()) < 0) {
perror("fork error");
exit(1);
} else if (pid == 0) {
srand(time(NULL)); // 初始化随机数种子
while (1) {
// 随机选择一个选项
rand_num = rand() % 3;
printf("另一个玩家选择了 %d(%s)\n", rand_num,
(rand_num == 0 ? "石头" : rand_num == 1 ? "剪刀" : "布"));
// 将自己的选择写入共享内存
*shm_ptr = rand_num;
// 释放信号灯
V(semid);
// 等待另一玩家完成选择
P(semid);
}
exit(0);
}
// 父进程等待所有子进程结束
while (waitpid(-1, NULL, 0) != -1);
// 删除共享内存和信号灯
if (shmctl(shmid, IPC_RMID, 0) == -1) {
perror("shmctl error");
}
if (semctl(semid, 0, IPC_RMID) == -1) {
perror("semctl error");
}
return 0;
}
// P操作
void P(int semid) {
struct sembuf sem;
sem.sem_num = 0;
sem.sem_op = -1;
sem.sem_flg = SEM_UNDO;
semop(semid, &sem, 1);
}
// V操作
void V(int semid) {
struct sembuf sem;
sem.sem_num = 0;
sem.sem_op = 1;
sem.sem_flg = SEM_UNDO;
semop(semid, &sem, 1);
}
```
这个程序使用了共享内存和二元信号量来完成进程间通信(IPC),包括两个玩家进程和一个父进程。其中,玩家1进程从标准输入中读取用户的选择,并将选择写入共享内存;玩家2进程随机选择一个选项,并将其写入共享内存;父进程从共享内存中读取玩家1和玩家2的选择,判断胜负并输出结果。这个程序支持多次游戏,并统计每位玩家的胜负平局次数。
阅读全文