并行程序模拟

《算法竞赛入门经典》刘汝佳 6-1  并行程序模拟   P139

题目:

     在单处理器系统上同时执行的程序看起来是同时执行的,但实际上,单个CPU在程序之间交替,在切换到下一个程序之前从每个程序执行一些指令。您将在这样的系统上模拟最多十个程序的并发执行,并确定它们将产生的输出。

     当前正在执行的程序被称为运行,而所有等待执行的程序都被称为已准备好。一个程序由一个不超过25个语句的序列组成,每行一个,后面一个结束语句。下面列出的语句如下所示。

Statement Type    Syntax
Assignment      variable = constant
Output         print variable
Begin Mutual Exclusion lock
End Mutual Exclusion    unlock
Stop Execution             end

       变量是任何一个小写字母字符,常数是一个小于100的无符号十进制数。在计算机系统中只有26个变量,并且它们在程序之间共享。因此,对一个程序中的变量赋值会影响由不同程序打印的值。最初将所有变量设置为零。

         每个语句都需要一个整数的时间单位来执行。允许运行程序继续执行一段时间的指令,称之为量子。当程序的时间量子到期时,将选择另一个就绪程序来运行。当时间量子期满时,当前执行的任何指令都将被允许完成。

      程序先排好队列,以便在就绪队列中执行。就绪队列的初始顺序对应于输入文件中程序的原始顺序。但是,由于执行锁定和解锁语句,该顺序可能会改变。

     每当程序希望声明对其正在操作的变量的互斥访问时,就使用锁和解锁语句。这些语句总是成对出现,包围一个或多个其他语句。一个锁总是在解锁之前,这些语句永远不会嵌套。一个程序成功执行锁语句,除非锁程序运行并执行相应的解锁语句,否则没有其他程序可以成功执行锁语句。如果一个正在运行的程序试图在锁已经生效时执行锁,那么这个程序将被放置在阻塞队列的末尾。以这种方式被阻塞的程序失去它们当前的剩余量子余量。当执行解锁时,阻塞队列头上的任何程序都被移动到就绪队列的头部。该程序运行时的第一个语句将是以前失败的锁语句。请注意,通过正确使用锁和解锁语句来执行互斥协议取决于所涉及的程序。(一个没有锁/解锁对的叛变程序可以改变它希望的任何变量,尽管其他程序正确使用锁/解。

     Input

     输入以一行上的单个正整数开头,该行本身指示由空白行跟随的情况的数目,并且两个连续输入之间还有空白行。

     输入文件的第一行由七个由空间分隔的整数组成。这些整数指定(按顺序):随后的程序的数量、五个语句中的每个语句的单位执行时间(按上面给出的顺序)以及包含时间量的时间单位的数量。输入的其余部分由程序组成,这些程序是根据上述规则由语句正确形成的。

扫描二维码关注公众号,回复: 3482618 查看本文章

     所有的程序语句都从一行的第一列开始。在语句中出现的空白应该被忽略。根据每个程序在输入数据中的位置(第一个程序具有ID=1,第二个程序具有ID=2等),关联每个程序是一个标识号。

     Output

    对于每个测试用例,输出必须遵循下面的描述。两个连续情况的输出将被空白线分隔。

     输出将包含打印报表生成的输出,因为它们在模拟过程中发生。在执行打印语句时,程序应该显示程序ID、冒号、空格和所选变量的值。分开的打印语句的输出应该出现在不同的行上。

    样本输入和正确输出如下所示。

  

Sample Input

1
3 1 1 1 1 1 1

a = 4 print a

lock

b = 9

print b

unlock

print b

end

a = 3

print a

lock

b = 8

print b

unlock

print b

end

b = 5

a = 17

print a

print b

lock

b = 21

print b

unlock

print b

end


Sample Output

1: 3

2: 3

3: 17

3: 9

1: 9

1: 9

2: 8

2: 8

3: 21

3: 21

注:

       英文版的题目见https://blog.csdn.net/leo6033/article/details/80639945

      如果没有了解一点进程的知识,这道题目还是别看了。我上了操作系统,这道题目看半天。

      上面的链接也有程序答案,我改变了一点。我提取变量和对应大小的时候,采用了映射map。

      至于其他地方,看懂题目应该没啥难度。

代码:

#include<iostream>
#include<queue>
#include<string>
#include<vector>
#include<cstring>//memset()函数 
#include<map>//匹配变量和对应的值 
using namespace std;

deque<int> qr;
queue<int> qw; 
const int maxn=1005;
int t[5];//记录每条指令的时间 
int T;//记录时间片 
vector<string> prog[maxn];//记录程序内容 
int p[maxn];//用来记录第i个程序执行位置 
map<string,string> vars; 
bool lock=false;

void run(int i)
{
	int rt=T;
	string s;
	string var,cons;//表示变量和常量 
	while(rt>0)
	{
		s=prog[i][p[i]];
		if(s[2]=='=')
		{
			rt=rt-t[0]; 
			var=s[0];//默认变量名为char
			cons=s.substr(4);
			vars[var]=cons; 
		} 
		else if(s[2]=='i')
		{
			rt=rt-t[1];
			var=s.substr(6);
			cout<<i<<":"<<vars[var]<<endl;
		}
		else if(s[2]=='c')
		{
			rt=rt-t[2];
			if(lock)
			{
				qw.push(i);
				return ;
			}

			else
				lock=true;
		}
		else if(s[2]=='l')
		{
			rt=rt-t[3];
			lock=false;
			if(!qw.empty())
			{
				qr.push_front(qw.front());
				qw.pop();
			}
		}
		else
			return;
		p[i]++;
	}
}



int main()
{
	int cas;
	string s;
	cin>>cas;
	while(cas--)
	{
		int i,n;//n个程序并行 
		cin>>n;
		for(i=0;i<5;i++)//输入每条指令执行的时间 
		{              //'='  'print'  'lock'  'ulock'  'end'顺序 
			cin>>t[i];
		}
		cin>>T; //输入时间片 
		for(i=1;i<=n;i++)
		{
			prog[i].clear();//由于是在外部申请的,每次需要清空 
			while(getline(cin,s))
			{
				if(s=="")
					continue;//防止输入空行
				prog[i].push_back(s); 
				if(s=="end")
					break; 
			}
			qr.push_back(i);
		}
		memset(p,0,sizeof(p));
		while(!qr.empty())
		{
			int cur=qr.front();
			qr.pop_front();
			run(cur);
			qr.push_back(cur);
		}
		if(cas)
			cout<<endl; 
	}
} 

参考文章:

双端队列:http://www.cplusplus.com/reference/deque/deque/?kw=deque

猜你喜欢

转载自blog.csdn.net/sinat_38816924/article/details/82846302
今日推荐