内容仅作记录,解答有参考别人的地方,请谨慎参考。关于锁,文中我很随意的说法是“上锁”与“开锁”,文雅一点的说法可以说“获取锁”和“释放锁”。
首先输入指令:./x86.py -p flag.s运行程序:
可以看到两个线程在执行,再使用指令:cat flag.s查看汇编代码:
由此我们可以分析出程序代码的大致含义:实现一个简单的自旋锁
大致的程序代码如下:
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);
}
可以看到程序产生了正确的结果,之后分析代码标志(flag)的变化:
由第一题分析,得出程序和锁的大致代码
void lock(int flag)//线程T0将要执行,需要上锁
{
while(flag==1);//flag初始为0,所以成功得到锁,自旋停止
flag=1;//之后将flag设置为1,在该线程临界区执行完之前,其他线程一直自旋
}
void unlock(int flag)//线程临界区中的内容执行完,开锁
{
flag=0;//设置flag为0,其他线程可以上锁
}
for(int i=1;i>0;i--)
{
lock(flag);
count++;//CS
unlock(flag);
}
由此可以分析标志flag的值的变化,与模拟结果是一致的
通过第一题中对汇编代码的分析,我们可以知道,这个程序对count进行循环加1操作,并且锁保护的方案为“细粒度”方案(将锁上在循环内部),将bx修改为2时,相当于增加了循环的次数,所以程序所作的工作如下:
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);
}
这个时候,由于中断频率很慢(指中断发生之前,一个线程可以执行完),而且程序做了两次循环,所以我们将会看到一个线程在执行过程中做了两次上锁与开锁。由于循环两次,并且有两个线程,所以count的结果最终为4。
输入指令:./x86.py -p flag.s -R ax,bx -M flag,count -a bx=2,bx=2 -c运行程序查看结果:
可以看到模拟运行结果与分析是一致的。
当中断发生在正在执行的线程开锁之前时,将导致不好的结果,这是因为当前线程尚未执行完,标志flag仍为1,即使中断发生,另一个线程也无法获得锁的使用,这段时间里该线程占用了CPU,但并未做任何事,只是在进行自旋等待中断发生。
例如:将中断频率设置为4:
输入指令:./x86.py -p flag.s -R ax,bx -M flag,count -a bx=4,bx=4 -i 4 -c运行程序查看结果:
以前几个中断周期为例,最开始线程T0得到了锁,并将标志flag设置为了1,这时中断发生,由于中断频率较高,T0并未开锁,flag仍为1,当T1开始执行时将一直执行“while(flag==1)”这条语句,也就是说在这个过程中T1一直占用CPU,但并未执行程序内容,所以当中断频率过快或中断发生在线程开锁之前时,将会导致不好的结果,相对的,中断频率刚好发生在一个线程开锁之后将会使CPU得到充分的利用,可以认为是一个好的结果。
分析汇编代码,可以大致分析出上锁和开锁的代码:
首先利用一个交换函数,这个函数将会把1赋给mutex,之后返回mutex的旧值
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);
}
代码总能够按照预期进行工作,但第四题中的问题依然存在,当中断发生在当前执行的线程开锁之前时,将导致另一个线程即使得到了CPU的使用权,也只是占用CPU做自旋,在这种情况下CPU的使用率是不高的。
输入指令:./x86.py -p test-and-set.s -i 7 -R ax,bx -M mutex,count -a bx=5 -c查看程序运行的情况:
[这里我故意将中断设置为7条指令进行一次,是为了让问题更明显]
观察图中红色方框框选的部分可以看到,这时线程T1已经获得了CPU的使用权,但是该线程只是在循环执行“while(swap(1,mutex)==1);”并未进入临界区进行操作,这种情况下CPU的使用率是很低的。
当每次中断发生在当前线程开锁之前时,将会导致中断后执行的线程一直进行自旋而无法执行相应的操作,导致CPU利用率低,要使CPU利用率得到提高,需要在当前线程释放锁之后再执行中断。
输入指令:./x86.py -p test-and-set.s -i 10 -R ax,bx -M mutex,count -a bx=5 -P 000011111111 -c模拟在第一个线程中获取锁之后在尝试第二个线程中获取锁的过程:
可以看到,当第一个线程获取锁之后,随后在另一个线程中尝试获取锁是无法成功,也无法进入临界区执行代码,只有在当前拥有锁的线程释放锁之后,另一个线程才能成功获取锁,由此说明这个锁具有使未获得锁的线程进入临界区的功能,正确的事情发生了。
还需要测试的是当拥有锁的线程释放锁之后,另一个线程再获取锁是否能够成功
由上面的模拟结果就能看到这个测试结果:
可以看到,当线程T0释放锁之后,T1再次获取锁成功,随后成功进入临界区执行,这说明这个锁在释放之后,其他线程可以获取锁,锁的功能正常。