一、Linux共享内存函数
Linux中共享内存函数有shmget、shmat、shmdt、shmctl。所有函数都封装在sys.shm.h头文件中。
这是sys.shm.h头文件
/* Copyright (C) 1995-2020 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#ifndef _SYS_SHM_H
#define _SYS_SHM_H 1
#include <features.h>
#define __need_size_t
#include <stddef.h>
/* Get common definition of System V style IPC. */
#include <sys/ipc.h>
/* Get system dependent definition of `struct shmid_ds' and more. */
#include <bits/shm.h>
/* Define types required by the standard. */
#include <bits/types/time_t.h>
#ifdef __USE_XOPEN
# ifndef __pid_t_defined
typedef __pid_t pid_t;
# define __pid_t_defined
# endif
#endif /* X/Open */
__BEGIN_DECLS
/* The following System V style IPC functions implement a shared memory
facility. The definition is found in XPG4.2. */
/* Shared memory control operation. */
extern int shmctl (int __shmid, int __cmd, struct shmid_ds *__buf) __THROW;
/* Get shared memory segment. */
extern int shmget (key_t __key, size_t __size, int __shmflg) __THROW;
/* Attach shared memory segment. */
extern void *shmat (int __shmid, const void *__shmaddr, int __shmflg)
__THROW;
/* Detach shared memory segment. */
extern int shmdt (const void *__shmaddr) __THROW;
__END_DECLS
#endif /* sys/shm.h */
1.shmget()函数
shmget(得到一个共享内存标识符或创建一个共享内存对象) | ||
所需头文件 | #include <sys/ipc.h> #include <sys/shm.h> | |
函数说明 | 得到一个共享内存标识符或创建一个共享内存对象并返回共享内存标识符 | |
函数原型 | int shmget(key_t key, size_t size, int shmflg) | |
函数传入值 | key | 0(IPC_PRIVATE):会建立新共享内存对象 |
大于0的32位整数:视参数shmflg来确定操作。通常要求此值来源于ftok返回的IPC键值 | ||
size | 大于0的整数:新建的共享内存大小,以字节为单位 | |
0:只获取共享内存时指定为0 | ||
shmflg | 0:取共享内存标识符,若不存在则函数会报错 | |
IPC_CREAT:当shmflg&IPC_CREAT为真时,如果内核中不存在键值与key相等的共享内存,则新建一个共享内存;如果存在这样的共享内存,返回此共享内存的标识符 | ||
IPC_CREAT|IPC_EXCL:如果内核中不存在键值 与key相等的共享内存,则新建一个共享内存;如果存在这样的共享内存则报错 | ||
函数返回值 | 成功:返回共享内存的标识符 | |
出错:-1,错误原因存于errno中 | ||
附加说明 | 上述shmflg参数为模式标志参数,使用时需要与IPC对象存取权限(如0600)进行|运算来确定信号量集的存取权限 | |
错误代码 | EINVAL:参数size小于SHMMIN或大于SHMMAX EEXIST:预建立key所指的共享内存,但已经存在 EIDRM:参数key所指的共享内存已经删除 ENOSPC:超过了系统允许建立的共享内存的最大值(SHMALL) ENOENT:参数key所指的共享内存不存在,而参数shmflg未设IPC_CREAT位 EACCES:没有权限 ENOMEM:核心内存不足 |
2.shmat()函数
shmat(把共享内存区对象映射到调用进程的地址空间) | ||
所需头文件 | #include <sys/types.h> #include <sys/shm.h> | |
函数说明 | 连接共享内存标识符为shmid的共享内存,连接成功后把共享内存区对象映射到调用进程的地址空间,随后可像本地空间一样访问 | |
函数原型 | void *shmat(int shmid, const void *shmaddr, int shmflg) | |
函数传入值 | shmid | 共享内存标识符 |
shmaddr | 指定共享内存出现在进程内存地址的什么位置,直接指定为NULL让内核自己决定一个合适的地址位置 | |
shmflg | SHM_RDONLY:为只读模式,其他为读写模式 | |
函数返回值 | 成功:附加好的共享内存地址 | |
出错:-1,错误原因存于errno中 | ||
附加说明 | fork后子进程继承已连接的共享内存地址。exec后该子进程与已连接的共享内存地址自动脱离(detach)。进程结束后,已连接的共享内存地址会自动脱离(detach) | |
错误代码 | EACCES:无权限以指定方式连接共享内存 EINVAL:无效的参数shmid或shmaddr ENOMEM:核心内存不足 |
实现猜拳游戏主要就使用了这两个函数,后面两个函数的用法可以自行百度,这里就过多介绍了。
二、实现思路
使用三个进程来分别代表裁判和两个玩家,三个进程通过共享内存实现数据共享。裁判进程负责根据两个玩家输入来判断胜负,并将结构写入数据结构中。两个玩家进程完成数据的输入。
三、实现代码
裁判进程referee.c:
#include <stdio.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <unistd.h>
#include <sys/types.h>
#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define KEY 166 //共享内存标识
#define SIZE 3277
int main()
{
typedef struct
{
int player1;
int player2;
int result;
} Game; //游戏数据结构
int shmid;
void *shm = NULL;
Game *shared;
shmid = shmget(KEY, sizeof(Game), IPC_CREAT | 0600); // 获取共享内存
if (shmid < 0)
{
printf("ERROR\n");
}
else
{
printf("sucess\n");
} // crt
shm = shmat(shmid, NULL, 0);//获取共享内存指针
if (shm == (void *)-1)
{
printf("ERROR\n");
}
else
{
printf("success\n");
}
shared = (Game *)shm;
printf("Game Start");
while (1)
{
if (shared->player1 == 0 || shared->player2 == 0)
{
printf("waiting for players...\n");
sleep(1);
}
if (shared->player1 == shared->player2 && shared->player1 != 0 && shared->player2 != 0)
{
shared->result = 3;
printf("The two players drew.\n");
break;
}
if (shared->player1 == 3 && shared->player2 == 2)
{
shared->result = 1;
printf("player1 win\n");
break;
}
if (shared->player1 == 3 && shared->player2 == 1)
{
shared->result = 2;
printf("player2 win\n");
break;
}
if (shared->player1 == 2 && shared->player2 == 3)
{
shared->result = 2;
printf("player2 win\n");
break;
}
if (shared->player1 == 2 && shared->player2 == 1)
{
shared->result = 1;
printf("player1 win\n");
break;
}
if (shared->player1 == 1 && shared->player2 == 3)
{
shared->result = 1;
printf("player1 win\n");
break;
}
if (shared->player1 == 1 && shared->player2 == 2)
{
shared->result = 2;
printf("player2 win\n");
break;
}
}
sleep(5);
shared->result = 0;
shared->player1 = 0;
shared->player2 = 0;
return 0;
}
玩家进程player1.c:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/shm.h>
#define SIZE 3277
#define KEY 166
int main()
{
typedef struct
{
int player1;
int player2;
int result;
} Game;
void *shm = NULL;
Game *shared = NULL;
int fuck[SIZE];
int shmid;
shmid = shmget(KEY, sizeof(Game), IPC_CREAT | 0600);
if (shmid < 0)
{
printf("ERROR\n");
}
else
{
printf("success\n");
}
shm = shmat(shmid, NULL, 0);
if (shm == (void *)-1)
{
printf("ERROR\n");
}
shared = (Game *)shm;
while (1)
{
if (shared->player1 == 0)
{
int l;
printf("Enter number\n");
scanf("%d", &shared->player1);
}
else if (shared->result != 0)
{
switch (shared->result)
{
case 1:
printf("You win.\n");
break;
case 2:
printf("You lost.\n");
break;
case 3:
printf("The two players drew.\n");
break;
}
break;
}
else
{
printf("Waiting for the opponent\n");
sleep(1);
}
}
return 0;
}
玩家进程2player2:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/shm.h>
#define SIZE 3277
#define KEY 166
int main()
{
typedef struct
{
int player1;
int player2;
int result;
} Game;
void *shm = NULL;
Game *shared = NULL;
int fuck[SIZE];
int shmid;
shmid = shmget(KEY, sizeof(Game), IPC_CREAT | 0600);
if (shmid < 0)
{
printf("ERROR\n");
}
else
{
printf("Success\n");
}
shm = shmat(shmid, NULL, 0);
if (shm == (void *)-1)
{
printf("ERROR\n");
}
shared = (Game *)shm;
while (1)
{
if (shared->player2 == 0)
{
int l;
printf("Enter number\n");
scanf("%d", &shared->player2);
}
else if (shared->result != 0)
{
switch (shared->result)
{
case 1:
printf("You lost.\n");
break;
case 2:
printf("You win.\n");
break;
case 3:
printf("The two players drew.\n");
break;
}
break;
}
else
{
printf("Waiting for the opponent\n");
sleep(1);
}
}
return 0;
}
四、运行结果
打开三个终端分别运行三个进程
玩家分别输入后
以上。。。