这次实验做的东西不多,看得东西比较多,一开始容易发晕。这里赵博士的《注释》发挥了巨大作用,好好研习深有帮助啊。
不多说,看实验:
首先是内存跟踪,因为实验指导书写的实在是很详细,这里就不说了,也没什么好说的了;
接下来是Ubuntu的内存共享:
这里就是我觉得比较恶心的地方就是,网上得解决方案都不行;
比如说用ftok函数生成key的那个,我试来试去就是过不了,网上也有说Linux这个函数会出错,唉,我就没对过。
后来想到一个方法,就是用信号量把shm_id传过去,在下一个进程通过getvalue()得到shm_id,这样的话,完全大才小用了,但是,实在试不出来了,后来有人跟我说,直接给key赋值一个整数,只要不是内部已有的key,就可以,我试了一下,可能是理解原因,没成功。不过通过信号量的话,就绕过了这个key值,让系统来自动生成一个,同样可以成功。
在生产者中,把信号量初值定义为shm_id
if((semShmid = sem_open("4444",O_CREAT,0777,shm_id)) == SEM_FAILED)
printf("Sem_t4 error!");
在消费者中:
if((semShmid = sem_open("4444",O_CREAT,0777,10)) == SEM_FAILED)
printf("Sem_t4 error!");
sem_getvalue(semShmid,&shm_id);
sem_unlink("4444");
得到shm_id
这样就成功了;
其他的这里就不多说了。
接下来是系统调用,调用过程大家应该很熟悉了,不记得的话前面几篇博客有讲;
主要是这次的两个系统调用:
int sys_shmget(key_t key,size_t size,int shmflg)
这个的话,先做一个key值判重,就像上次信号量一样,接下来就是申请一片物理内存,这里系统有函数封装好的:
get_free_page()
返回值是物理内存号;
大家可以在内核申请一个数组保存,返回值吗,就是只要找的到你保存在哪里就好了。
void *sys_shmat(int shmid,void *addr,int shmflg)
这个系统调用得话:
首先根据key,找到你存放物理内存的地点,数组也好,链表也好。
接下来就是建立映射:
实验指导书最后几段暗示的很明确;让你在进程空闲的数据段开辟内存,这里给个图:
你看,有用的长度就是brk,后面的就是你要申请的地方。
这里只给出提示,得到brk长度:
current->brk
其他的,不能太多嘴。
这次的源码不超过50行,就不帖了。。。主要是理解原理(赵博士的书啊)
这里最后会有一个错误,Try to free free page.
这个问题,的原因就是,你在一个进程里面申请了一个共享内存,在另一个进程也同样用到了这个内存页,所以,系统在return的时候销毁两次同一块内存,于是,出现了这种状况。(在memory.c里有free_page函数)
解决方案1:直接把panic那句注释掉。这样程序就不会终止了;
解决方案2:把前面mem_map数组值加1,赵博士书里面有提到,默认在被申请的情况下是1的,这样就可以被减两次了。。。。
解决方案3:在shmget函数里面,每get一个,就把mem_map加1,这种做法最好,最符合逻辑,但是,我没有尝试过,理论上可行。上面两个做法多多少少有点问题。