UVa 210 Concurrency Simulator [并发模拟,双端队列]

题意

模拟并发,n个程序切换进行,共享变量。每个时刻只能有一个程序在运行,每次运行分配了大小为quantum的时间,在一时间内运行程序中耗时为t[i]的指令。

运行quantum时间后,程序进入[准备队列]队尾。指令lock在实际的并发中作用是申请对变量独占访问(本题中只改变程序顺序),如果已经有一个程序执行了lock,另一个程序再次执行lock将会被添加到[阻塞队列]队尾,quantum直接结束,不进入[准备队列]。直到原lock程序执行unlock,[阻塞队列]队首程序出队,进入[等待队列]队首。

分析

[等待队列]可以插入队首,因此是个[双端队列]。每一个程序执行到哪条指令可以用一个指针/索引表示。

代码

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<vector>
  4 #include<string>
  5 #include<queue>
  6 #include<deque>
  7 #include<cstring>
  8 
  9 using namespace std;
 10 
 11 typedef struct {
 12     vector<string> statements;    //存放指令语句
 13     int eip = 0;    //当前指令指针
 14     bool pushed = 0;    //标志程序是否入阻塞队
 15 } Program;
 16 
 17 vector<Program> programs; 
 18 
 19 int test_cases, n, t[5], q, vars[26];
 20 
 21 queue<int> blocked_queue;    //push pop
 22 deque<int> ready_queue;    //push_front push_back pop_front pop_back
 23 
 24 bool glock = 0;
 25 int pid, time_count;
 26 
 27 void assign_ins()
 28 {
 29     int &eip = programs[pid].eip;
 30     string &ins = programs[pid].statements[eip];
 31     int int_const = stoi(ins.substr(4)); //v = ?
 32     vars[ins[0] - 'a'] = int_const;
 33     
 34     eip++;
 35     time_count += t[0];
 36 }
 37 
 38 void print_ins()
 39 {
 40     int &eip = programs[pid].eip;
 41     char var = programs[pid].statements[eip][6];
 42     printf("%d: %d\n", pid+1, vars[var - 'a']);
 43     
 44     eip++;
 45     time_count += t[1];
 46 }
 47 
 48 bool lock_ins()
 49 {
 50     //不考虑重复锁
 51     if(glock) //当前已经有锁
 52     {
 53         if(!programs[pid].pushed)
 54         {
 55             blocked_queue.push(pid);
 56             programs[pid].pushed = 1;
 57         }
 58         time_count += q; //锁住的情况下,什么都做不了,直接超时
 59         return 0;
 60     }
 61     else {
 62         glock = 1;
 63         
 64         programs[pid].eip++;
 65         time_count += t[2];
 66         return 1;
 67     }
 68 }
 69 
 70 void unlock_ins()
 71 {
 72     glock = 0;
 73     if(!blocked_queue.empty())
 74     {
 75         int blocked_id = blocked_queue.front(); blocked_queue.pop();
 76         programs[blocked_id].pushed = 0; //从等待队列中释放
 77         ready_queue.push_front(blocked_id);
 78     }
 79     
 80     programs[pid].eip++;
 81     time_count += t[3];
 82 }
 83 
 84 void end_ins()
 85 {
 86     programs[pid].eip++; //eip == programs[pid].statements.size()
 87     time_count += q;
 88 }
 89 
 90 
 91 int main()
 92 {
 93     scanf("%d", &test_cases);
 94     while(test_cases--)
 95     {
 96         scanf("%d", &n);
 97         for(int i = 0; i < 5; i++)
 98             scanf("%d", t+i);
 99         scanf("%d ", &q);
100         
101         memset(vars, 0, sizeof(vars));
102         programs.clear();
103         programs.resize(n);
104         
105         string str;
106         for(int i = 0; i < n; i++)
107             while(getline(cin, str))
108             {
109                 programs[i].statements.push_back(str);
110                 if(str[2] == 'd')
111                     break;
112             }
113         
114         //程序入队
115         for(int i = 0; i < n; i++)
116             ready_queue.push_back(i);
117 
118         while(!ready_queue.empty())
119         {
120             pid = ready_queue.front(); ready_queue.pop_front();
121             time_count = 0;
122             
123             bool ready_flag = 1;
124             while(time_count < q) //程序时间内
125             {
126                 int &eip = programs[pid].eip;
127                 switch(programs[pid].statements[eip][2]) //变量名问题,不能用首字符
128                 {
129                     case '=':
130                         assign_ins();
131                         break;
132                     case 'i':
133                         print_ins();
134                         break;
135                     case 'c':
136                         ready_flag = lock_ins();
137                         break;
138                     case 'l':
139                         unlock_ins();
140                         break;
141                     case 'd':
142                         end_ins();
143                         ready_flag = 0;
144                         break;
145                     default:
146                         break;
147                 }
148             }
149             if(ready_flag)
150                 ready_queue.push_back(pid);
151         }
152         if(test_cases > 0)
153             printf("\n");
154     }
155     return 0;
156 }

小结

写代码过程中的bug总结:

1.一定要注意保证循环可以退出,循环不能正常退出,输出会混乱(甚至不符合代码逻辑)。特别注意:*循环条件不是计数,而是队列为空之类的判断,保证队列一定会运行到为空。

2.根据输入条件选择对应处理时,要看清楚判断方式会不会干扰,比如本题中"end"和“e = 1”首字符str[0]都为'e',所以不能选首字符判断。

3.一些标志位,比如Program.pushed,置为1之后要注意有对应的地方将其置为0。

一些扩展的想法:在本题基础上实现并发控制,给IO操作设置耗时t > quantum,不放入准备队列。IO完成产生中断,把它插到准备队列队首。lock后,其他执行修改共享变量的程序进入阻塞队列,等unlock。以上是瞎想的。

posted @ 2019-04-15 18:32  fool_bird  阅读(144)  评论(0)    收藏  举报