UVa 210 Concurrency Simulator [併發模擬,雙端隊列]

題意

模擬併發,n個程序切換進行,共享變量。每一個時刻只能有一個程序在運行,每次運行分配了大小爲quantum的時間,在一時間內運行程序中耗時爲t[i]的指令。ios

運行quantum時間後,程序進入[準備隊列]隊尾。指令lock在實際的併發中做用是申請對變量獨佔訪問(本題中只改變程序順序),若是已經有一個程序執行了lock,另外一個程序再次執行lock將會被添加到[阻塞隊列]隊尾,quantum直接結束,不進入[準備隊列]。直到原lock程序執行unlock,[阻塞隊列]隊首程序出隊,進入[等待隊列]隊首。併發

分析

[等待隊列]能夠插入隊首,所以是個[雙端隊列]。每個程序執行到哪條指令能夠用一個指針/索引表示。spa

代碼

  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.必定要注意保證循環能夠退出,循環不能正常退出,輸出會混亂(甚至不符合代碼邏輯)。特別注意:*循環條件不是計數,而是隊列爲空之類的判斷,保證隊列必定會運行到爲空。code

2.根據輸入條件選擇對應處理時,要看清楚判斷方式會不會干擾,好比本題中"end"和「e = 1」首字符str[0]都爲'e',因此不能選首字符判斷。blog

3.一些標誌位,好比Program.pushed,置爲1以後要注意有對應的地方將其置爲0。索引

一些擴展的想法:在本題基礎上實現併發控制,給IO操做設置耗時t > quantum,不放入準備隊列。IO完成產生中斷,把它插到準備隊列隊首。lock後,其餘執行修改共享變量的程序進入阻塞隊列,等unlock。以上是瞎想的。隊列

相關文章
相關標籤/搜索