问答题
阅读以下技术说明和C语言代码,根据要求回答问题1至问题6。
【说明】
有两个进程(编号分别为0和1)需要访问同一个共享资源。为了解决竞争条件(race condition)的问题,需要实现一种互斥机制,使得在任何时刻只能有一个进程访问该共享资源。以下【C代码1】给出了一种实现方法。
【C代码1】
int flag[2]; /+flag数组,初始化为FALSE*/
Enter_Critical_Section(int my_task_id, int other_task_id)
{ while (flag[other_task_id]==TRUE); /*空循环语句*/
flag[my_task_id]=TRUE;
}
Exit_Critical_Section(int my_task_id, int other_task_id)
{ flag[my_task_id]=FALSE;
}
当一个进程要访问临界资源时,就可以调用【C代码1】给出的这两个函数。【C代码2】给出了进程0的一个例子。
【C代码2】
Enter_Critical_Section(0,1);
……使用这个资源……
Exit_Critical_Section(0,1);
……做其他的事情……
问答题
【问题1】
什么是临界资源(critical resource)?请用100字以内的文字简要说明。
【正确答案】
【答案解析】在多道程序系统中,各进程可以共享各类资源,但有些资源一次只能供一个进程使用。需要互斥访问的资源称为临界资源 [要点解析] 在多道程序系统中,各进程可以共享各类资源,但有些资源一次只能供一个进程使用。需要互斥访问的资源称为临界资源(Critical Resource),如打印机、共享变量和表格等。
问答题
【问题2】
【C代码1】所示的方法{{U}} (1) {{/U}}实现共享资源的互斥访问。
(1) A.能够 B.不能
【正确答案】
【答案解析】B或不能 [要点解析] 【C代码1】所示的方法不能实现资源的互斥访问。例如,考虑如下的情形。 1)初始化的时候,flag数组的两个元素值均为FALSE: 2)进程0先执行,在执行while循环语句时,由于flag[1]=FALSE,所以程序顺利结束,不会被卡住,假设此时出现一个时钟中断,打断它的运行; 3)进程1去执行,在执行while循环语句时,由于flag[0]=FALSE,所以程序顺利结束,不会被卡住,然后就进入了临界区; 4)当进程0再执行时,也进入了临界区,这样就同时有两个进程在临界区。
问答题
【问题3】
【C代码1】采用了一种繁忙等待(busy waiting)的策略,这种策略的缺点是什么?请用100字以内的文字简要说明。
【正确答案】
【答案解析】由于该算法策略每个任务进程要循环地去判断当前能否访问临界资源,因此会浪费大量的CPU时间,而且如果设计不合理,容易导致死锁 [要点解析] 本题考查的是进程之间的互斥问题,即基于繁忙等待(Busy Waiting)的进程互斥实现方法。其基本思路是,当一个进程要进入临界区,首先需要检查是否允许它进入,若允许,则直接进入;否则,则循环等待。 在多道程序系统中,各个进程是并发执行的,由于时钟中断的原因,使进程之间的执行顺序变得难以预测,每个进程都有可能在任意一条语句的后面被中断。在这种情况下,如果要采用基于繁忙等待的互斥实现方法,就必须考虑所有的可能情况,即如果每个进程在不同的位置被中断时,能否正确地实现进程间互斥。 由于该算法策略需要使用一个循环语句不断执行测试指令,即每个进程要循环地判断当前能否访问临界资源,因此会浪费大量的CPU时间,而且如果设计不合理,容易导致死锁。
问答题
【问题4】
如果把Enter_Critical_Section()函数中的两条语句互换一下位置,则可能会出现什么情况?
【正确答案】
【答案解析】可能会出现死锁 [要点解析] 在“Enter_Critical_Section(int my_task_jd, int other_task_id)”函数中,已提示“while(flag[other_task_id]==TRUE);”是一条空循环语句。如果将它调到“flag[my_task_id]=TRUE;”语句之后,将导致程序进入死锁状态。
问答题 【问题5】 【C代码3】中x,y是两个已定义的整型变量。对该程序段进行覆盖测试时,必须适当地选取测试用例。如表5-10所示给出了可供选择的4组测试用例。若要实现语句覆盖,则至少应采用的测试用例是{{U}} (2) {{/U}};若要实现条件覆盖,则至少应采用的测试用例是{{U}} (3) {{/U}};若要实现路径覆盖,则至少应采用的测试用例是{{U}} (4) {{/U}}或{{U}} (5) {{/U}}。 【C代码3】 int a:=0; if (x==O && y>2) a:=1 /*A语句*/ else { if (x<1 || y==1) else a:=2 /*B语句*/ } {{B}}表5-10 测试用例表{{/B}}{{/B}}
变 量
x
y
 测试用例Ⅰ  0  3
 测试用例Ⅱ  1  2
 测试用例Ⅲ  -1  2
 测试用例Ⅳ  3  1
【(2)~(5)空缺处供选择的答案】
A.Ⅰ和Ⅱ组 B.Ⅱ和Ⅲ组
C.Ⅲ和Ⅳ组 D.Ⅰ和Ⅳ组
E.Ⅰ、Ⅱ和Ⅲ组 F.Ⅱ、Ⅲ和Ⅳ组G.Ⅰ、Ⅲ和Ⅳ组 H.Ⅰ、Ⅱ和Ⅳ组
【正确答案】
【答案解析】
问答题
【问题6】
程序的环路复杂度V(G)也称为McCabe复杂性度量,它是构成基本路径集的独立路径数的上界,可依此得出应该设计的测试用例数目。请计算【C代码3】程序段的环路复杂度V(G)。
【正确答案】
【答案解析】V(G)=3 [要点解析] 这是一道要求读者计算程序环路复杂度的试题。本题的解答思路如下。 程序的环路复杂度V(G)也称为McCabe复杂性度量,通常将它定义为程序控制流图(见图5-13)的区域数,它是构成基本路径集的独立路径数的上界,可依此得出应该设计的测试用例数目。 在进行程序的基本路径测试时,从程序的环路复杂度可导出程序基本路径集合中的独立路径条数,以确保程序中每个可执行语句至少执行一次所必须的测试用例数目的上界。 计算控制流图环路复杂性V(G)的一种简单方法是:V(G)=(区域数)=(判断节点数)+1。阅读图5-13的程序控制流图可知,该图的判断节点数为2个((x=0)and(y>2)和(x<1)or(y=1)),因此【C代码3】程序段的环路复杂度V(G)=2+1=3。