UVa210-并行程序模拟

重点在于字符串处理和双端队列的实现,一般的队列是队首出队,队尾入队。

题目的情景是,当一个进程解除上锁时,处于阻止队列队首的进程直接插入到等待队列的队首。

  • 思路

处理输入的时候,将每个进程作为一个结构体,里面维护当前进程执行到第几条指令,当前进程包含的指令,每条指令对应的类型,进程id,以及该进程包含几条指令。在输入的时候就要把这些信息处理好。

等待队列和阻止队列存的都是进程id号,而不是指令,指令的执行是具有并发性的。

初始将进程id按顺序一个一个推进等待队列。

对于每一个运行态的进程,都有时间片的限制,这个quantum配额是统一。执行时,按照FIFO将队首进程提为running状态,执行指令要接着之前的进度往下执行,而且根据指令的不同,每条指令所需时间不同,还要采取不同的措施:

如果是赋值,不仅占用时间,还要更改相应变量的值,同时,因为是以字符串形式给出的这个值,要有一个不断*10获得这个数值的处理;

如果是输出,则占用时间并把对应变量的值输出;

如果是上锁,则要看当前是否已经有进程上了锁,因此维护一个相对于执行过程的全局变量lock_situation,如果没有进程已经拿了锁,那么当前进程就可以上锁,并修改lock_situation,否则,就将该变量送入阻止队列,如果当前进程还有时间片剩余,也只能浪费;

如果是解锁,就要还原lock_situation变量,判断阻止队列是否为空,如果不为空,就要把阻止队列的队首出队,插入到等待队列的队首;

如果是结束,就不要再把这个进程插入等待队列了。所有指令都要记住更新进程执行到第几条指令。

因为进程去了阻止队列或者所有指令执行完毕就不会再去等待队列,所以每个进程提上running态的时候都维护两个标志变量to_block和to_end,以判断这一轮执行完后还要不要再把进程塞进等待队列。

  • 从数据结构的实现上,要注意的点是:

从队首插入要注意,一般的循环队列front指向的队首元素的前一个位置,这个位置永远不占元素,所以在队首插入的时候应该先放值再移动队首指针。

一定注意队列max_size和开辟数组大小的统一。不能开queue[20],但是max_size却设成1000,这样做就会出现奇怪现象:因为越界,碰到了别人的地盘,值无缘无故改变了 。

判空判满的条件要烂熟于心,即使不记得,也可以自己在纸上进行推理。

  • 对于这道题目本身,要注意的点是:

题目的input和sample input不相符合,第一个整数是整个测试用例数,但是sample input并没有给出来。

这道题目就是多个基本知识的综合,要有耐心,并能一个部分一个部分地写好。

// 值无缘无故改变是因为越界了,碰到了别人的地盘 
// 队列开的大小要和maxsize匹配 
#include <cstdio>
#include <cstring>
#include <algorithm>
// 最多10个程序,每个程序不超过25条指令 
using namespace std;
int programs = 0; // 程序数 
int assign_unit = 0;
int output_unit = 0;
int lock_unit = 0;
int unlock_unit = 0;
int end_unit = 0;
int quantum = 0;

int value[30] = {0}; // 26个变量的值

int front_wait = 0, rear_wait = 0;
int maxsize = 1000;
//int wait_queue[20] = {0}; // 等待队列 
int wait_queue[1000] = {0};
int front_block = 0, rear_block = 0;
//int block_queue[20] = {0}; // 阻止队列 
int block_queue[1000] = {0};
typedef struct program{
	int cur_end;// 当前每个程序的第几条指令完成了 
	char statement[30][100];
	int type[30];
	int id;
	int cnt; // 有几条指令 
}program;
program Program[15] = {0};

void init() {
	memset(Program, 0, sizeof(Program));
	memset(value, 0, sizeof(value)); 
	front_wait = 0, rear_wait = 0;
	front_block = 0, rear_block = 0;
	return;
}

inline int is_blank(char c) {
	return c == '\n' || c == ' ' || c == '\t';
}

void test_input() {
	for (int i = 1; i <= programs; i++) {
		printf("program id: %d\n", i);
		
		for (int j = 0; j < Program[i].cnt; j++) {
			printf("type: %d, %s\n", Program[i].type[j], Program[i].statement[j]);
		}
		printf("\n");
	}
	return;
}

int Enque_rear(int which, int x) { // 队尾插入 
	if (which == 0) { // 等待队列
		if ((rear_wait + 1) % maxsize == front_wait) { // 队列满 
			return -1;
		}
		rear_wait = (rear_wait + 1) % maxsize;
		wait_queue[rear_wait] = x;
	} else { // 阻止队列 
		if ((rear_block + 1) % maxsize == front_block) {
			return -1;
		}
		rear_block = (rear_block + 1) % maxsize;
		block_queue[rear_block] = x;
	}
	return 1;
}

int Enque_front(int which, int x) { // 队首插入 
	if (which == 0) { // 等待队列 
		if ((front_wait - 1) % maxsize == rear_wait) { // 队列满 
			return -1;
		}
		// front指向的是队头元素的前一个 
		wait_queue[front_wait] = x;
		front_wait = (front_wait - 1) % maxsize;
		
	} else { // 阻止队列 
		if ((front_block - 1) % maxsize == rear_block) {
			return -1;
		}
		block_queue[front_block] = x;
		front_block = (front_block - 1) % maxsize;
	}
	return 1;
}

int Deque(int which) { // 队头出队 

	if (which == 0) { // 等待队列 
		if (front_wait == rear_wait) { // 队列空 
			return -1;
		}
		front_wait = (front_wait + 1) % maxsize;
		return wait_queue[front_wait];
		
	} else { // 阻止队列 
		if (front_block == rear_block) {
			return -1;
		}
		front_block = (front_block + 1) % maxsize;
		return block_queue[front_block];
	}
}

int main() {
//	freopen("data.in", "r", stdin);
	
	
	int T;
	scanf("%d", &T);
	int start = 0;
	while (T--) {
		if (start == 0) {
			start = 1;
		} else {
			printf("\n");
		}
		scanf("%d", &programs);
		scanf("%d%d%d%d%d%d", &assign_unit, &output_unit, &lock_unit, &unlock_unit, &end_unit, &quantum);
		init(); 
		int program = 1;
		char temp[100] = {0};
		while (fgets(temp, 101, stdin) != NULL) {
			if (temp[strlen(temp) - 1] == '\n') {
				temp[strlen(temp) - 1] = 0;
			}
			char *p = temp;
			while (is_blank(*p)) {
				p++;
			}
			if ((*p) == '\0') {
				continue;
			}
			
			int cur_state = Program[program].cnt;
			strcpy(Program[program].statement[cur_state], temp);
			if (strchr(temp, '=') != NULL) {
				Program[program].type[cur_state] = 1; // 赋值语句 
			} else if (temp[0] == 'p') {
				Program[program].type[cur_state] = 2; // 打印语句 
			} else if (temp[0] == 'l') {
				Program[program].type[cur_state] = 3; // 上锁 
			} else if (temp[0] == 'u') {
				Program[program].type[cur_state] = 4; // 解锁 
			} else if (strcmp(temp, "end") == 0) {
				Program[program].type[cur_state] = 5; // end 
			}
			Program[program].cnt++;
			if (Program[program].type[cur_state] == 5) { // end
				program++;
				if (program == programs + 1) {
					break;
				}
			}
		} 
//		test_input();
		for (int i = 1; i <= programs; i++) {
			Enque_rear(0, i);
		}
		int lock_situation = 0;
		while (front_wait != rear_wait) { // 等待队列不为空 
			int cur_id = Deque(0); // 等待队列队首
			int left = quantum;
			int to_block = 0;
			int to_end = 0;
			while (left > 0) {
				char cur_statement = (Program[cur_id].cur_end);	 //这句话应该放在里面,放在外面就超时,当前语句一直不更新 
				int cur_type = Program[cur_id].type[cur_statement];
				
				if (cur_type == 1) {
					left -= assign_unit;
					char character = Program[cur_id].statement[cur_statement][0];
					int temp = Program[cur_id].statement[cur_statement][4] - '0';
					if (Program[cur_id].statement[cur_statement][5] != 0) {
						temp = temp * 10 + Program[cur_id].statement[cur_statement][5] - '0';
					}
					if (Program[cur_id].statement[cur_statement][6] != 0) {
						temp = temp * 10 + Program[cur_id].statement[cur_statement][6] - '0';
					}
					value[character-'a'] = temp;
					Program[cur_id].cur_end++;
				} else if (cur_type == 2) {
					left -= output_unit;
					Program[cur_id].cur_end++;
					char character = Program[cur_id].statement[cur_statement][6];
					printf("%d: %d\n", cur_id, value[character-'a']);
				} else if (cur_type == 3) {
					if (lock_situation == 0) {
						lock_situation = 1;
						left -= lock_unit;
						Program[cur_id].cur_end++;
					} else {
						Enque_rear(1, cur_id); // 去了阻止队列就不会去等待队列了 
						left = 0;
						to_block = 1;
						break;
					}
				} else if (cur_type == 4) {
					lock_situation = 0; 
					left -= unlock_unit;
					Program[cur_id].cur_end++;
					int block_id = Deque(1);
					if (block_id != -1) {
						Enque_front(0, block_id);
					} 
				} else if (cur_type == 5) {
					left -= end_unit;
					to_end = 1;
					Program[cur_id].cur_end++;
					left = 0; 
				}
			} 
			if (to_block == 1 || to_end == 1) {
				continue;
			}
			if (Program[cur_id].cur_end != Program[cur_id].cnt) {
				Enque_rear(0, cur_id);
			}
		}
	}
	return 0;
} 
posted @ 2021-02-06 19:14  Mo_hw  阅读(211)  评论(0编辑  收藏  举报