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

本文详细分析了使用自旋锁实现的并发控制,探讨了中断如何影响进程执行,尤其是在不同中断频率下对计数器count的影响。通过实例展示了合理与不合理中断场景,以及锁设计对CPU利用率的关键影响,包括互斥性和性能提升策略。
摘要由CSDN通过智能技术生成

第一题

输入指令:
在这里插入图片描述
可以看到两个线程按照顺序在执行,接下来输入指令: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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值