题目描述:内存分配
Time Limit: 1000MS |
| Memory Limit: 10000K |
Total Submissions: 2831 |
| Accepted: 650 |
Description
内存是计算机重要的资源之一,程序运行的过程中必须对内存进行分配。
经典的内存分配过程是这样进行的:
1. 内存以内存单元为基本单位,每个内存单元用一个固定的整数作为标识,称为地址。地址从0开始连续排列,地址相邻的内存单元被认为是逻辑上连续的。我们把从地址i开始的s个连续的内存单元称为首地址为i长度为s的地址片。
2. 运行过程中有若干进程需要占用内存,对于每个进程有一个申请时刻T,需要内存单元数M及运行时间P。在运行时间P内(即T时刻开始,T+P时刻结束),这M个被占用的内存单元不能再被其他进程使用。
3、假设在T时刻有一个进程申请M个单元,且运行时间为P,则:
1. 若T时刻内存中存在长度为M的空闲地址片,则系统将这M个空闲单元分配给该进程。若存在多个长度为M个空闲地址片,则系统将首地址最小的那个空闲地址片分配给该进程。
2. 如果T时刻不存在长度为M的空闲地址片,则该进程被放入一个等待队列。对于处于等待队列队头的进程,只要在任一时刻,存在长度为M的空闲地址片,系统马上将该进程取出队列,并为它分配内存单元。注意,在进行内存分配处理过程中,处于等待队列队头的进程的处理优先级最高,队列中的其它进程不能先于队头进程被处理。
现在给出一系列描述进程的数据,请编写一程序模拟系统分配内存的过程。
Input
第一行是一个数N,表示总内存单元数(即地址范围从0到N-1)。从第二行开始每行描述一个进程的三个整数T、M、P(M <= N)。最后一行用三个0表示结束。
数据已按T从小到大排序。
输入文件最多10000行,且所有数据都小于109。
输入文件中同一行相邻两项之间用一个或多个空格隔开。
Output
包括2行。
第一行是全部进程都运行完毕的时刻。
第二行是被放入过等待队列的进程总数。
Sample Input
10
1 3 10 2 4 3 3 4 4 4 1 4 5 3 4 0 0 0
Sample Output
12 2
主要思路:定义全局变量
三个链表:
1:内存信息链表(双链表)按照起始地址从小到大排列
用来保存当前的内存资源信息
2:进程结束时刻链表按照结束时刻从小到大排列
用来保存将要结束的进程信息
3:进程等待队列 先进先出
用来保存等待进程的信息;
定义全局变量:
byte global_flag;
/*global_flag:正常读文件时 flag=2; 遇到文件结束flag=1;队列结束并且flag=1 是将flag=0*/
mem_chain *mem_top; /*指向内存资源链表表头指针 */
mem_chain *mem_tail; /*指向内存资源链表表尾指针 */
end_chain *end_top; /*指向进程结束时刻链表的头尾指针*/
end_chain *end_tail; /*指向进程结束时刻链表的表尾指针*/
wait_que *wait_top; /*指向任务等待 队列的队首指针*/
wait_que *wait_tail; /*指向任务等待 队列的队尾指针*/
可以讲系统分为五部来运行:
首先初始化全局变量:
void os_init ( )
{
mem_top = mem_tail = NULL;
end_top = end_tail = NULL;
wait_top = wait_tail = NULL;
global_flag = 2;
time_cnt = 0;
wait_cnt = 0;
}
然后就开始
读进去第一个数据创建内存资源链表
读进去第一个进程的信息
void os_begin( )
{
uint16 mem_size;
scanf("%d", & mem_size );
mem_chain *node;
node = (mem_chain *)calloc (1,sizeof(mem_chain));
node -> mem_info.begin = 1;
node -> mem_info.size = (mem_type) mem_size;
node -> mem_info.end = (mem_type) mem_size;
add_mem ( node );
read_next_cour( );
}
然后就开始运行:
主要函数:
void os_run ( void )
{
mem_chain *temp_node;
end_chain *temp_end;
wait_que *temp_wait;
for (time_cnt = 1 ; global_flag ; time_cnt ++) {
/*从每一个时刻开始,如果有进程在此时结束:
1:更改内存资源链表 add_mem ( temp_node );
2:更改进程结束时刻链表 free_end ( );
注意可能有多个进程在此时结束 */
while(1){
if(end_top != NULL &&
end_top -> cour_info.end_time == time_cnt ){
temp_node = (mem_chain * )calloc (1 ,sizeof ( mem_chain ));
temp_node -> mem_info.begin = end_top -> mem_info.begin;
temp_node -> mem_info.end = end_top -> mem_info.end;
temp_node -> mem_info.size = end_top -> mem_info.size;
add_mem ( temp_node );
free_end ( );
}
if ( end_top == NULL ||
end_top -> cour_info.end_time > time_cnt )
break;
}
/*如果 有等待队列的队首元素可以在此时运行 就运行:
1:增加任务结束时刻链表 add_end ( );
2:修改等待队列 free_wait( );
3:修改内存资源 sub_mem ( );
否则什么也不做*/
if ( wait_top != NULL && (temp_node = app_mem ( wait_top -> size )) != NULL ){
temp_end = (end_chain *)calloc (1,sizeof (end_chain));
temp_end -> mem_info.size = wait_top -> size;
temp_end -> mem_info.begin = temp_node -> mem_info.begin;
temp_end -> mem_info.end = temp_node -> mem_info.begin + wait_top -> size;
temp_end -> cour_info.app_time = time_cnt ;
temp_end -> cour_info.run_time = wait_top -> run_time;
temp_end -> cour_info.end_time = time_cnt + wait_top -> run_time;
add_end ( temp_end );
free_wait( );
sub_mem ( temp_node , temp_end -> mem_info.size );
}
/*在这个时刻根据global_flag信息是否判断进程节点D到时 ,
若到时就判断是否可以运行
1)可以运行则:
1:修改内存资源
2:增加进程结束时刻链表
3:读入下一个进程节点
2)不可以运行则:
1: 进程D进入等待队列
2:读入下一个信息
3:等待计数变量++ */
if(global_flag == 2 && D.app_time == time_cnt ){
if( (temp_node = app_mem ( D.size ) ) != NULL ){
temp_end = (end_chain *)calloc (1,sizeof (end_chain));
temp_end -> mem_info.size = D.size;
temp_end -> mem_info.begin = temp_node -> mem_info.begin;
temp_end -> mem_info.end = temp_node -> mem_info.begin + D.size;
temp_end -> cour_info.app_time = D.app_time;
temp_end -> cour_info.run_time = D.run_time;
temp_end -> cour_info.end_time = D.end_time;
sub_mem (temp_node , D.size );
add_end ( temp_end );
read_next_cour ( );
}
else {
temp_wait = (wait_que * )calloc (1, sizeof(wait_que ));
temp_wait -> size = D.size;
temp_wait -> run_time = D.run_time;
add_wait (temp_wait );
read_next_cour( );
wait_cnt ++;
}
}
}
}
在上面有两个函数需要注意:
1:释放进程结束链表的节点:
void free_end ( void )
{
end_chain *temp;
if ( end_top -> next == NULL ){
free(end_top );
end_top = end_tail = NULL;
if(global_flag == 1 && wait_top == NULL )
global_flag = 0;
}
/*注意此时如果global_flag== 1 表示已经读到末尾,若wait_top == NULL则表示也不从在等待进程了,此时将global_flag 置零,即退出os_run函数;*/
else {
temp = end_top -> next;
end_top -> next -> prev = NULL;
free ( end_top );
end_top = temp;
}
return ;
}
void free_wait( )
{
wait_que * temp;
if(wait_top -> next == NULL ){
free (wait_top );
wait_top = wait_tail = NULL;
if(global_flag == 1)
global_flag = 0;
/*这里如果global_flag == 1,则表示读到结尾,此时等待队列又为空则将
global_flag 置零,即退出os_run函数;*/
}
else {
temp = wait_top -> next;
free (wait_top );
wait_top = temp;
}
return ;
}
注意 增加内存资源的时候实际就是将一个内存资源节点挂到链表上此时需要注意新增的内存在内存资源的头部尾部。。
新增的内存可以与原有的内存组成的一块更大的内存,还是仅仅是一个独立的内存块全部代码如下所示:
cour_node D; /*用来存放下一个进程的信息*/
cour_type time_cnt; /*运行的时刻 */
cour_type wait_cnt; /*等待过的进程的个数*/