实验报告
实验内容
进程间通信—共享内存。实现一个带有 n 个单元的线性表的并发维护。
- 建立一个足够大的共享内存空间 (lock, M),逻辑值 lock 用来保证同一时间只有一个进程进入 M;测试你的系统上 M 的上限。
- 设计一个程序在 M 上建立一个结点信息结构为 (flag, 学号, 姓名) 的静态链表 L,逻辑值 flag 用作结点的删除标识;在 L 上建立一个以学号为关键字的二元小顶堆,自行设计控制结构 (如静态指针数据域)。
- 设计一个程序对上述堆结构的结点实现插入、删除、修改、查找、重排等操作。该程序的进程可以在多个终端并发执行。
- 思考:使用逻辑值 lock 实现的并发机制不能解决条件冲突问题。
实验环境
Ubuntu 20.04.2.0(64位)
实验过程
一. 测试本机共享内存空间的上限
- 通过
ipcs -l
可以直接显示本机共享内存的限制,为18014398509465599kbytes,但显然实际用时不可能有这么大的空间可用。
- 编写代码进行测试
设计思路: 改边共享内存的大小,每次创建更大空间的共享内存。
每次内存大小乘2,当共享内存大小超过7085490176时再乘以2将超出可申请内存的大小。
二. 程序实现
(一)整个程序分为三个部分:
labweek7.h
: 头文件,包含各种结构体和说明。labweek7.c
: 控制台,用于最开始创建共享内存和最后删除共享内存。labweek7-0.c
: 进行实际操作(小顶堆)和通信的程序。
(二)演示
- 先运行控制台,创建共享内存,同时初始化lock。
2. 运行两个 labweek7-0.c
程序
输入一个任意数,第一个可以继续往下运行,第二个被卡住无法继续运行。
- 演示:
①pop: 先在第一个进程中执行,空堆提示。
②insert: 插入三个学生。
③stop: 暂停执行该进程,同时另一个进程继续往下执行。
④pop: 输出学号最小的同学的信息同时将他从堆中删除。
⑤insert: 再插入4个学生。
⑥search: 查找19335266的学生,未找到;再查找19335278的学生,找到并输出。
⑦stop: 暂停执行该进程,回到另一个进程继续往下执行。
⑧change: 修改学号最小的学生的信息并重排。
⑨pop: pop直到堆空,刚好6个学生,且按学号从小到大输出。
⑩quit: 该进程退出,另一个进程继续执行,之后也退出,最后控制台也退出。
三. 思考
lock不能协调多进程之间的条件冲突问题。
四. 代码
- labweek7.h
#define NameSize 21/* = PAGE_SIZE, size of each message */
#define LinkSize 100 /* maximal number of static link */
/* total size can not exceed current shmmax,
or an 'invalid argument' error occurs when shmget */
typedef struct{
int flag;
unsigned int id; /* student's id*/
char name[NameSize]; /* student's name*/
}Link;
/* a demo structure, modified as needed */
struct shared_struct {
int lock; /* lock = 0: labweek7-0 run; lock = 1: labweek7-1 run; lock = -1: quit*/
Link link[LinkSize+1]; /* static link: from 1 to LinkSize*/
int count; /* the counter of array*/
};
#define PERM S_IRUSR|S_IWUSR|IPC_CREAT
#define ERR_EXIT(m) \
do { \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
- labweek7.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/shm.h>
#include <fcntl.h>
#include "labweek7.h"
int main(int argc, char *argv[])
{
struct stat fileattr;
key_t key; /* of type int */
int shmid; /* shared memory ID */
void *shmptr;
struct shared_struct *shared; /* structured shm */
// pid_t childpid1, childpid2;
char pathname[80], key_str[10], cmd_str[80];
int shmsize, ret;
shmsize = /*LinkSize**/sizeof(struct shared_struct);
printf("max record number = %d, shm size = %d\n", LinkSize, shmsize);
if(argc <2) {
printf("Usage: ./a.out pathname\n");
return EXIT_FAILURE;
}
// sscanf(argv[1], "%x", &key);
strcpy(pathname, argv[1]);
if(stat(pathname, &fileattr) == -1) {
ret = creat(pathname, O_RDWR);
if (ret == -1) {
ERR_EXIT("creat()");
}
printf("shared file object created\n");
}
key = ftok(pathname, 0x27); /* 0x27 a project ID 0x0001 - 0xffff, 8 least bits used */
if(key == -1) {
ERR_EXIT("shmcon: ftok()");
}
printf("key generated: IPC key = %x\n", key); /* can set any nonzero key without ftok()*/
shmid = shmget((key_t)key, shmsize, 0666|PERM);
if(shmid == -1) {
ERR_EXIT("shmcon: shmget()");
}
printf("shmcon: shmid = %d\n", shmid);
shmptr = shmat(shmid, 0, 0); /* returns the virtual base address mapping to the shared memory, *shmaddr=0 decided by kernel */
if(shmptr == (void *)-1) {
ERR_EXIT("shmcon: shmat()");
}
printf("shmcon: shared Memory attached at %p\n", shmptr);
shared = (struct shared_struct *)shmptr;
shared->lock = 0;
shared->count = 0;
sprintf(cmd_str, "ipcs -m | grep '%d'\n", shmid);
printf("\n------ Shared Memory Segments ------\n");
system(cmd_str);
if(shmdt(shmptr) == -1) {
ERR_EXIT("shmcon: shmdt()");
}
printf("\n------ Shared Memory Segments ------\n");
system(cmd_str);
while(1){
int num;
printf("Enter number(0: run; -1: quit)\n");
scanf("%d", &num);
if(num == -1){
if (shmctl(shmid, IPC_RMID, 0) == -1) {
ERR_EXIT("shmcon: shmctl(IPC_RMID)");
}
else {
printf("shmcon: shmid = %d removed \n", shmid);
printf("\n------ Shared Memory Segments ------\n");
system(cmd_str);
printf("nothing found ...\n");
}
break;
}
}
exit(EXIT_SUCCESS);
}
- labweek7-0.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <string.h>
#include <sys/shm.h>
#include "labweek7.h"
void push(Link *link, int i);
void change(Link *minHeap, int n);
int main(int argc, char *argv[])
{
void *shmptr = NULL;
struct shared_struct *shared;
int shmid;
key_t key;
key = ftok(argv[1], 0x27);
// sscanf(argv[1], "%x", &key);
printf("labweek7-0: IPC key = %x\n", key);
shmid = shmget((key_t)key, /*LinkSize**/sizeof(struct shared_struct), 0666|PERM);
if (shmid == -1) {
ERR_EXIT("labweek7-0: shmget()");
}
shmptr = shmat(shmid, 0, 0);
if(shmptr == (void *)-1) {
ERR_EXIT("labweek7-0: shmat()");
}
printf("labweek7-0: shmid = %d\n", shmid);
printf("labweek7-0: shmsize = %ld\n", sizeof(struct shared_struct));
printf("labweek7-0: shared memory attached at %p\n", shmptr);
printf("labweek7-0 process ready ...\n");
shared = (struct shared_struct *)shmptr;
// shared->count = 0;
// shared->lock = 0;
while (1) {
// if(shared->lock == 0){
int r;
printf("If you want to continue this program, enter a random number:\n");
scanf("%d", &r);
// }
while(shared->lock == 1){
sleep(1);
}
shared->lock = 1;
while(1){
int ope;
printf("Enter operation(0: insert; 1: put the first node and delete; 2: change the first node; 3: search; 4: stop; 5: quit)\n");
scanf("%d", &ope);
if(ope == 0){
if(shared->count == LinkSize){
printf("The heap is full!\n");
}
else{
shared->count++;
printf("Enter the student's information(ID and name): \n");
scanf("%u", &shared->link[shared->count].id);
getchar();
fgets(shared->link[shared->count].name, NameSize, stdin);
printf("Insert a student: %u %s\n", shared->link[shared->count].id, shared->link[shared->count].name);
push(shared->link, shared->count);
}
}
else if(ope == 1){
if(shared->count == 0){
printf("The heap is empty!\n");
}
else{
printf("The first student(node): %u %s\n", shared->link[1].id, shared->link[1].name);
shared->link[1] = shared->link[shared->count--];
change(shared->link, shared->count);
printf("This student delete!\n");
}
}
else if(ope == 2){
if(shared->count == 0){
printf("The heap is empty!\n");
}
else{
printf("Enter the student's information that you want to change(ID and name): \n");
scanf("%u", &shared->link[1].id);
getchar();
fgets(shared->link[1].name, NameSize, stdin);
printf("Change the first student(node): %u %s\n", shared->link[1].id, shared->link[1].name);
change(shared->link, shared->count);
printf("This student change!\n");
}
}
else if(ope == 3){
unsigned int ID;
int c = 1;
printf("Enter the student's id that you want to search: \n");
scanf("%u", &ID);
while(c <= shared->count){
if(ID == shared->link[c].id){
printf("The student is: %d %s\n", shared->link[c].id, shared->link[c].name);
break;
}
c++;
}
if(c == shared->count + 1){
printf("This student is not exist!\n");
}
}
else if(ope == 4){
shared->lock = 0;
break;
}
else if(ope == 5){
shared->lock = -1;
break;
}
else {
printf("Invalid input.\n");
continue;
}
}
if(shared->lock == -1){
// shared->lock = 1;
break;
}
} /* it is not reliable to use shared->written for process synchronization */
if (shmdt(shmptr) == -1) {
ERR_EXIT("shmcon: shmdt(IPC_RMID)");
}
// sleep(1);
exit(EXIT_SUCCESS);
}
void push(Link *link, int i)
{
while((i>>1) >= 1 && link[i].id < link[i>>1].id){
Link t = link[i];
link[i] = link[i>>1];
link[i>>1] = t;
i = i>>1;
}
}
void change(Link *minHeap, int n)
{
// int a = minHeap[1];
// minHeap[1] = minHeap[n+1];
int i = 1;
while((i<<1) <= n){
if((i<<1)+1 > n){
if(minHeap[i].id > minHeap[(i<<1)].id){
Link t = minHeap[i];
minHeap[i] = minHeap[(i<<1)];
minHeap[(i<<1)] = t;
i = (i<<1);
}else{
break;
}
}else{
if((minHeap[i].id > minHeap[(i<<1)].id && minHeap[i].id <= minHeap[(i<<1) + 1].id) || (minHeap[i].id > minHeap[(i<<1)].id && minHeap[i].id > minHeap[(i<<1) + 1].id && minHeap[(i<<1)].id < minHeap[(i<<1) + 1].id)){
Link t = minHeap[i];
minHeap[i] = minHeap[(i<<1)];
minHeap[(i<<1)] = t;
i = (i<<1);
}else if((minHeap[i].id <= minHeap[(i<<1)].id && minHeap[i].id > minHeap[(i<<1) + 1].id) || (minHeap[i].id > minHeap[(i<<1)].id && minHeap[i].id > minHeap[(i<<1) + 1].id && minHeap[(i<<1)].id >= minHeap[(i<<1) + 1].id)){
Link t = minHeap[i];
minHeap[i] = minHeap[(i<<1) + 1];
minHeap[(i<<1) + 1] = t;
i = (i<<1) + 1;
}else{
break;
}
}
}
}