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;
}