《操作系统导论》第二十八章作业

第一题

输入指令:
在这里插入图片描述
可以看到两个线程按照顺序在执行,接下来输入指令:cat flag.s查看该程序代码:

.var flag
.var count

.main
.top

.acquire
mov  flag, %ax      # get flag
test $0, %ax        # if we get 0 back: lock is free!
jne  .acquire       # if not, try again
mov  $1, flag       # store 1 into flag

# critical section
mov  count, %ax     # get the value at the address
add  $1, %ax        # increment it
mov  %ax, count     # store it back

# release lock
mov  $0, flag       # clear the flag now

# see if we're still looping
sub  $1, %bx
test $0, %bx
jgt .top	

halt

通过分析,我们看到这个程序通过变量flag实现了一个自旋锁,类似的C代码为:

void lock(int flag)
{
	while(flag==1);
	flag=1;
}
void unlock(int flag)
{
	flag=0;
}
for(int i=1;i>0;i--)
{
	lock(flag);
	count++;
	unlock(int flag);

}

第二题

输入指令:./x86.py -p flag.s -R ax,bx -M flag,count 时,我们可以得到如下的结果:
在这里插入图片描述
通过书本上的知识,我们知道不合理的中断主要影响的是count的值,我们知道进程0和进程1都运行了一次count++,所有最后count的值应该是2,下面输入指令:./x86.py -p flag.s -R ax,bx -M flag,count -c时,可以得到如下的结果:
在这里插入图片描述
我们发现结果是正确的,flag.s按照预期的工作,我们预测的结果是正确的。

第三题

由于将bx的值修改为2,根据第一题的分析,我们知道了进程0和进程1的循环次数都会因为寄存器bx值的修改而发生变化,同时bx并不是进程0和进程1所共享的变量,所以进程0和进程1都会循环两次,所以count最后的值应该为4,类似的C程序代码为:

void lock(int flag)
{
	while(flag==1);
	flag=1;
}
void unlock(int flag)
{
	flag=0;
}
for(int i=2;i>0;i--)
{
	lock(flag);
	count++;
	unlock(flag);
}

输入指令:./x86.py -p flag.s -R ax,bx -M flag,count -a bx=2,bx=2 -c时我们可以看到结果为:

 flag count      ax    bx          Thread 0                Thread 1         

    0     0       0     2   
    0     0       0     2   1000 mov  flag, %ax
    0     0       0     2   1001 test $0, %ax
    0     0       0     2   1002 jne  .acquire
    1     0       0     2   1003 mov  $1, flag
    1     0       0     2   1004 mov  count, %ax
    1     0       1     2   1005 add  $1, %ax
    1     1       1     2   1006 mov  %ax, count
    0     1       1     2   1007 mov  $0, flag
    0     1       1     1   1008 sub  $1, %bx
    0     1       1     1   1009 test $0, %bx
    0     1       1     1   1010 jgt .top
    0     1       0     1   1000 mov  flag, %ax
    0     1       0     1   1001 test $0, %ax
    0     1       0     1   1002 jne  .acquire
    1     1       0     1   1003 mov  $1, flag
    1     1       1     1   1004 mov  count, %ax
    1     1       2     1   1005 add  $1, %ax
    1     2       2     1   1006 mov  %ax, count
    0     2       2     1   1007 mov  $0, flag
    0     2       2     0   1008 sub  $1, %bx
    0     2       2     0   1009 test $0, %bx
    0     2       2     0   1010 jgt .top
    0     2       2     0   1011 halt
    0     2       0     2   ----- Halt;Switch -----  ----- Halt;Switch -----  
    0     2       0     2                            1000 mov  flag, %ax
    0     2       0     2                            1001 test $0, %ax
    0     2       0     2                            1002 jne  .acquire
    1     2       0     2                            1003 mov  $1, flag
    1     2       2     2                            1004 mov  count, %ax
    1     2       3     2                            1005 add  $1, %ax
    1     3       3     2                            1006 mov  %ax, count
    0     3       3     2                            1007 mov  $0, flag
    0     3       3     1                            1008 sub  $1, %bx
    0     3       3     1                            1009 test $0, %bx
    0     3       3     1                            1010 jgt .top
    0     3       0     1                            1000 mov  flag, %ax
    0     3       0     1                            1001 test $0, %ax
    0     3       0     1                            1002 jne  .acquire
    1     3       0     1                            1003 mov  $1, flag
    1     3       3     1                            1004 mov  count, %ax
    1     3       4     1                            1005 add  $1, %ax
    1     4       4     1                            1006 mov  %ax, count
    0     4       4     1                            1007 mov  $0, flag
    0     4       4     0                            1008 sub  $1, %bx
    0     4       4     0                            1009 test $0, %bx
    0     4       4     0                            1010 jgt .top
    0     4       4     0                            1011 halt

发现,与我们的分析是相符合的,我们知道flag.s的程序的实现是成功的。

第四题

刚开始,看到这题的时候,会想到可能是中断引起的临界区的竞争从而造成的错误,后面发现我们已经实现了锁。所以,我们这里判断的可能是一个程序的性能,如果中断在进程0开始执行的地方(即进程0获得了锁),进程1开始运行,会一直自旋,占用了CPU但是不会产生作用,所以可以认为在进程0刚开始运行的时候中断,然后进程1开始自旋占用CPU是一种不好的结果。这里,我们举个例子,当时钟中断频率为5的时候的结果为

 flag count      ax    bx          Thread 0                Thread 1         

    0     0       0     2   
    0     0       0     2   1000 mov  flag, %ax
    0     0       0     2   1001 test $0, %ax
    0     0       0     2   1002 jne  .acquire
    1     0       0     2   1003 mov  $1, flag
    1     0       0     2   1004 mov  count, %ax
    1     0       0     2   ------ Interrupt ------  ------ Interrupt ------  
    1     0       1     2                            1000 mov  flag, %ax
    1     0       1     2                            1001 test $0, %ax
    1     0       1     2                            1002 jne  .acquire
    1     0       1     2                            1000 mov  flag, %ax
    1     0       1     2                            1001 test $0, %ax
    1     0       0     2   ------ Interrupt ------  ------ Interrupt ------  
    1     0       1     2   1005 add  $1, %ax
    1     1       1     2   1006 mov  %ax, count
    0     1       1     2   1007 mov  $0, flag
    0     1       1     1   1008 sub  $1, %bx
    0     1       1     1   1009 test $0, %bx
    0     1       1     2   ------ Interrupt ------  ------ Interrupt ------  
    0     1       1     2                            1002 jne  .acquire
    0     1       0     2                            1000 mov  flag, %ax
    0     1       0     2                            1001 test $0, %ax
    0     1       0     2                            1002 jne  .acquire
    1     1       0     2                            1003 mov  $1, flag
    1     1       1     1   ------ Interrupt ------  ------ Interrupt ------  
    1     1       1     1   1010 jgt .top
    1     1       1     1   1000 mov  flag, %ax
    1     1       1     1   1001 test $0, %ax
    1     1       1     1   1002 jne  .acquire
    1     1       1     1   1000 mov  flag, %ax
    1     1       0     2   ------ Interrupt ------  ------ Interrupt ------  
    1     1       1     2                            1004 mov  count, %ax
    1     1       2     2                            1005 add  $1, %ax
    1     2       2     2                            1006 mov  %ax, count
    0     2       2     2                            1007 mov  $0, flag
    0     2       2     1                            1008 sub  $1, %bx
    0     2       1     1   ------ Interrupt ------  ------ Interrupt ------  
    0     2       1     1   1001 test $0, %ax
    0     2       1     1   1002 jne  .acquire
    0     2       0     1   1000 mov  flag, %ax
    0     2       0     1   1001 test $0, %ax
    0     2       0     1   1002 jne  .acquire
    0     2       2     1   ------ Interrupt ------  ------ Interrupt ------  
    0     2       2     1                            1009 test $0, %bx
    0     2       2     1                            1010 jgt .top
    0     2       0     1                            1000 mov  flag, %ax
    0     2       0     1                            1001 test $0, %ax
    0     2       0     1                            1002 jne  .acquire
    0     2       0     1   ------ Interrupt ------  ------ Interrupt ------  
    1     2       0     1   1003 mov  $1, flag
    1     2       2     1   1004 mov  count, %ax
    1     2       3     1   1005 add  $1, %ax
    1     3       3     1   1006 mov  %ax, count
    0     3       3     1   1007 mov  $0, flag
    0     3       0     1   ------ Interrupt ------  ------ Interrupt ------  
    1     3       0     1                            1003 mov  $1, flag
    1     3       3     1                            1004 mov  count, %ax
    1     3       4     1                            1005 add  $1, %ax
    1     4       4     1                            1006 mov  %ax, count
    0     4       4     1                            1007 mov  $0, flag
    0     4       3     1   ------ Interrupt ------  ------ Interrupt ------  
    0     4       3     0   1008 sub  $1, %bx
    0     4       3     0   1009 test $0, %bx
    0     4       3     0   1010 jgt .top
    0     4       3     0   1011 halt
    0     4       4     1   ----- Halt;Switch -----  ----- Halt;Switch -----  
    0     4       4     0                            1008 sub  $1, %bx
    0     4       4     0   ------ Interrupt ------  ------ Interrupt ------  
    0     4       4     0                            1009 test $0, %bx
    0     4       4     0                            1010 jgt .top
    0     4       4     0                            1011 halt

上述结果,就是一种不好的结果。那么好的结果是什么呢?
应该就是,进程0刚刚释放锁的时候,中断这个时候来了,正好开始运行进程1,这样的时钟中断频率就应该会导致产生良好的结果。所以当中断频率过快或中断发生在线程开锁之前时,将会导致不好的结果,相对的,中断频率刚好发生在一个线程开锁之后将会使CPU得到充分的利用,可以认为是一个好的结果。

第五题

使用指令查看程序test-and-set.c的代码:cat test-and-set.s,查看的结果如下:

在这里插入图片描述
xchg指令是一个交换指令,将锁设置为1,同时将锁旧的值保存下来,进行判断如果等于0就继续往下执行,否则停在这里自旋。类似的C程序代码如下:

int swap(int new,int mutex)
{
	int old=mutex;
	mutex=new;
	return old;
}
之后程序写法与第一题中分析一致:
void lock(int mutex)//获取锁
{
	while(swap(1,mutex)==1);
}
void unlock(int mutex)//释放锁
{
	mutex=0;
}
for(int i=n;i>0;i--)
{
	lock(mutex);
	count++;
	unlock(mutex);
}

第六题

首先,由于设置锁的原因,所以代码肯定可以按照预期工作,但是可能出现第四题中的情况。就是出现在进程0刚获得锁的时候,进程1开始运行就会一直停在那里自旋,有时会导致CPU使用率不高。量化的标准,我觉得可以看CPU中执行自旋的部分占运行整个程序所需要的代码的百分比。
输入指令:./x86.py -p test-and-set.s -i 7 -R ax,bx -M mutex,count -a bx=2 -c查看预测的结果是否正确:

mutex count      ax    bx          Thread 0                Thread 1         

    0     0       0     2   
    0     0       1     2   1000 mov  $1, %ax
    1     0       0     2   1001 xchg %ax, mutex
    1     0       0     2   1002 test $0, %ax
    1     0       0     2   1003 jne  .acquire
    1     0       0     2   1004 mov  count, %ax
    1     0       1     2   1005 add  $1, %ax
    1     1       1     2   1006 mov  %ax, count
    1     1       0     2   ------ Interrupt ------  ------ Interrupt ------  
    1     1       1     2                            1000 mov  $1, %ax
    1     1       1     2                            1001 xchg %ax, mutex
    1     1       1     2                            1002 test $0, %ax
    1     1       1     2                            1003 jne  .acquire
    1     1       1     2                            1000 mov  $1, %ax
    1     1       1     2                            1001 xchg %ax, mutex
    1     1       1     2                            1002 test $0, %ax
    1     1       1     2   ------ Interrupt ------  ------ Interrupt ------  
    0     1       1     2   1007 mov  $0, mutex
    0     1       1     1   1008 sub  $1, %bx
    0     1       1     1   1009 test $0, %bx
    0     1       1     1   1010 jgt .top
    0     1       1     1   1000 mov  $1, %ax
    1     1       0     1   1001 xchg %ax, mutex
    1     1       0     1   1002 test $0, %ax
    1     1       1     2   ------ Interrupt ------  ------ Interrupt ------  
    1     1       1     2                            1003 jne  .acquire
    1     1       1     2                            1000 mov  $1, %ax
    1     1       1     2                            1001 xchg %ax, mutex
    1     1       1     2                            1002 test $0, %ax
    1     1       1     2                            1003 jne  .acquire
    1     1       1     2                            1000 mov  $1, %ax
    1     1       1     2                            1001 xchg %ax, mutex
    1     1       0     1   ------ Interrupt ------  ------ Interrupt ------  
    1     1       0     1   1003 jne  .acquire
    1     1       1     1   1004 mov  count, %ax
    1     1       2     1   1005 add  $1, %ax
    1     2       2     1   1006 mov  %ax, count
    0     2       2     1   1007 mov  $0, mutex
    0     2       2     0   1008 sub  $1, %bx
    0     2       2     0   1009 test $0, %bx
    0     2       1     2   ------ Interrupt ------  ------ Interrupt ------  
    0     2       1     2                            1002 test $0, %ax
    0     2       1     2                            1003 jne  .acquire
    0     2       1     2                            1000 mov  $1, %ax
    1     2       0     2                            1001 xchg %ax, mutex
    1     2       0     2                            1002 test $0, %ax
    1     2       0     2                            1003 jne  .acquire
    1     2       2     2                            1004 mov  count, %ax
    1     2       2     0   ------ Interrupt ------  ------ Interrupt ------  
    1     2       2     0   1010 jgt .top
    1     2       2     0   1011 halt
    1     2       2     2   ----- Halt;Switch -----  ----- Halt;Switch -----  
    1     2       3     2                            1005 add  $1, %ax
    1     3       3     2                            1006 mov  %ax, count
    0     3       3     2                            1007 mov  $0, mutex
    0     3       3     1                            1008 sub  $1, %bx
    0     3       3     1                            1009 test $0, %bx
    0     3       3     1   ------ Interrupt ------  ------ Interrupt ------  
    0     3       3     1                            1010 jgt .top
    0     3       1     1                            1000 mov  $1, %ax
    1     3       0     1                            1001 xchg %ax, mutex
    1     3       0     1                            1002 test $0, %ax
    1     3       0     1                            1003 jne  .acquire
    1     3       3     1                            1004 mov  count, %ax
    1     3       4     1                            1005 add  $1, %ax
    1     3       4     1   ------ Interrupt ------  ------ Interrupt ------  
    1     4       4     1                            1006 mov  %ax, count
    0     4       4     1                            1007 mov  $0, mutex
    0     4       4     0                            1008 sub  $1, %bx
    0     4       4     0                            1009 test $0, %bx
    0     4       4     0                            1010 jgt .top
    0     4       4     0                            1011 halt

可以看到,我们设置的时钟中断频率就会导致CPU的使用率不高,这样会导致CPU执行很多次自旋等待的操作。当每次中断发生在当前线程开锁之前时,将会导致中断后执行的线程一直进行自旋而无法执行相应的操作,导致CPU利用率低,要使CPU利用率得到提高,需要在当前线程释放锁之后再执行中断。

第七题

输入指令:./x86.py -p test-and-set.s -i 10 -R ax,bx -M mutex,count -a bx=5 -P 000011111111 -c模拟在第一个线程中获取锁之后在尝试第二个线程中获取锁的过程:

mutex count      ax    bx          Thread 0                Thread 1         

    0     0       0     5   
    0     0       1     5   1000 mov  $1, %ax
    1     0       0     5   1001 xchg %ax, mutex
    1     0       0     5   1002 test $0, %ax
    1     0       0     5   1003 jne  .acquire
    1     0       0     5   ------ Interrupt ------  ------ Interrupt ------  
    1     0       1     5                            1000 mov  $1, %ax
    1     0       1     5                            1001 xchg %ax, mutex
    1     0       1     5                            1002 test $0, %ax
    1     0       1     5                            1003 jne  .acquire
    1     0       1     5                            1000 mov  $1, %ax
    1     0       1     5                            1001 xchg %ax, mutex
    1     0       1     5                            1002 test $0, %ax
    1     0       1     5                            1003 jne  .acquire
    1     0       0     5   ------ Interrupt ------  ------ Interrupt ------  
    1     0       0     5   1004 mov  count, %ax
    1     0       1     5   1005 add  $1, %ax
    1     1       1     5   1006 mov  %ax, count
    0     1       1     5   1007 mov  $0, mutex

可以看到,当第一个线程获取锁之后,随后在另一个线程中尝试获取锁是无法成功,也无法进入临界区执行代码,只有在当前拥有锁的线程释放锁之后,另一个线程才能成功获取锁,由此说明这个锁具有使未获得锁的线程进入临界区的功能,正确的事情发生了。
还需要测试的是当拥有锁的线程释放锁之后,另一个线程再获取锁是否能够成功
下面的程序运行结果就可以验证这个结论是否正确:

   1     0       0     5   ------ Interrupt ------  ------ Interrupt ------  
    1     0       0     5   1004 mov  count, %ax
    1     0       1     5   1005 add  $1, %ax
    1     1       1     5   1006 mov  %ax, count
    0     1       1     5   1007 mov  $0, mutex
    0     1       1     5   ------ Interrupt ------  ------ Interrupt ------  
    0     1       1     5                            1000 mov  $1, %ax
    1     1       0     5                            1001 xchg %ax, mutex
    1     1       0     5                            1002 test $0, %ax
    1     1       0     5                            1003 jne  .acquire
    1     1       1     5                            1004 mov  count, %ax
    1     1       2     5                            1005 add  $1, %ax
    1     2       2     5                            1006 mov  %ax, count
    0     2       2     5                            1007 mov  $0, mutex
    0     2       1     5   ------ Interrupt ------  ------ Interrupt ------  
    0     2       1     4   1008 sub  $1, %bx
    0     2       1     4   1009 test $0, %bx
    0     2       1     4   1010 jgt .top
    0     2       1     4   1000 mov  $1, %ax
    0     2       2     5   ------ Interrupt ------  ------ Interrupt ------  
    0     2       2     4                            1008 sub  $1, %bx
    0     2       2     4                            1009 test $0, %bx
    0     2       2     4                            1010 jgt .top
    0     2       1     4                            1000 mov  $1, %ax
    1     2       0     4                            1001 xchg %ax, mutex
    1     2       0     4                            1002 test $0, %ax
    1     2       0     4                            1003 jne  .acquire
    1     2       2     4                            1004 mov  count, %ax

这说明这个锁在释放之后,其他线程可以获取锁,锁的功能正常。
综上,我们可以知道这个锁的设计是成功的,不仅可以满足在一个进程拥有锁的时候,另一个进程无法进入,同时在一个进程释放锁的时候,另一个进程可以拥有锁,完成了锁的互斥性。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
操作系统的定义:是一组控制和管理计算机软硬件资源,为用户提供便捷使用计算机的程序的集合。 基本功能:1.进程管理 2.存储管理 3.文件管理 4.设备管理 5.作业管理 基本组成: 1、驱动程序 最底层bai的、直接控制和监视各类硬件的部分,它du们的职zhi责是隐藏硬件的具体细节,并向dao其他部分提供一个抽象的、通用的接口。 2、内核 操作系统之最内核部分,通常运行在最高特权级,负责提供基础性、结构性的功能。 3、支承库(亦作“接口库”) 是一系列特殊的程序库,它们职责在于把系统所提供的基本服务包装成应用程序所能够使用的编程接口(API),是最靠近应用程序的部分。例如,GNU C运行期库就属于此类,它把各种操作系统的内部编程接口包装成ANSI C和POSIX编程接口的形式。 4、外围 所谓外围,是指操作系统中除以上三类以外的所有其他部分,通常是用于提供特定高级服务的部件。例如,在微内核结构中,大部分系统服务,以及UNIX/Linux中各种守护进程都通常被划归此列。 操作系统的分类:1.批处理系统 2.分时操作系统 3.实时操作系统 4.分布式操作系统 5.网络操作系统 6.嵌入式操作系统 操作系统的特点: 1、并发性: 是在计算机bai系统中同时存在多个程序,宏观上看,du这些程序是同时向前推进的。 在单CPU上,这些并发执行的程序是交替在CPU上运行的。 程序并发性体现在两个方面: 用户程序与用户程序之间的并发执行。 用户程序与操作系统程序之间的并发。 2、共享性: 资源共享是操作系统程序和多个用户程序共用系统中的资源。 3、 随机性: 随机性指:操作系统的运行是在一个随机的环境中,一个设备可能在任何时间向处理机发出中断请求,系统无法知道运行着的程序会在什么时候做什么事情。 4、虚拟 (virtual)是指通过技术将一个物理实体变成若干个逻辑上的对应物。在操作系统中虚拟的实现主要是通过分时的使用方法。显然,如果n是某一个物理设备所对应的虚拟逻辑设备数,则虚拟设备的速度必然是物理设备速度的1/n。 5、异步性:不确定性。同一程序和数据的多次运行可能得到不同的结果;程序的运行时间、运行顺序也具有不确定性;外部输入的请求、运行故障发生的时间难以预测。这些都是不确定性的表现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值