2 回答
TA贡献1898条经验 获得超8个赞
这个函数还是十分精妙的!但是有点儿绕
首先纠正一下你代码的错误,while(TestAndSet(&lock))之后是有个分号的,即
while(TestAndSet(&lock));
是个空语句,表示一直在这里死循环。而不是一个劲儿的运行criticalsection。下面说这个机制的原理。
一个线程运行到while(TestAndSet(&lock))这句的时候,
如果criticalsection没有被锁住,即lock值为false,那么传入TestAndSet()的参数为false,【【在函数体内:rv先被赋为false,然后*target被赋为true,然后返回rv(值为false)。运行的结果为:返回值为false,使线程跳出while循环,得以进入criticalsection;同时参数(即lock)被改为true,表示criticalsection被锁住】】,其他线程在当前线程没有出criticalsection之前(即运行lock=false这句之前),不能进入criticalsection。为什么呢,下面说
如果线程运行到while(TestAndSet(&lock))时,criticalsection被锁住了,即lock值为true,那么证明有其他线程在运行criticalsection的代码(如第一步所说),那么传入TestAndSet()函数的值为true,《《在函数体内:*target为传入的值(true),rv被赋为true,*target被赋值为true(原来就是true,赋值不改变什么),返回rv。那么运行结果是返回值是rv(true),lock也是true。因为返回值是true,所以while继续运行,lock还是true》》,所以传入TestAndSet()的参数依然是true。在上一句《《》》之间的过程又重新运行一遍,然后一遍又一遍。所以这个线程一直在while这里一直运行,不能进入criticalsection。
直到在criticalsection中的那个线程运行完criticalsection中的代码,即运行到lock=false这句,lock被赋为false。这时比较关键了,while中再次运行TestAndSet()的时候传入的参数变成了false,那么第一段中【【】】中的过程会运行一遍,即返回值为false,在while中运行了无数次的进程可以跳出while,进入criticalsection,lock又重新被赋为true,即锁住criticalsection,其他进程此时不能进入。
所以“这条语句”的作用就是:如果当前criticalsection被锁定,那么在这里等,直到解锁;如果没有被锁定,当前进程可以进入criticalsection,同时锁定criticalsection。
上面就是原理了,下面说硬同步。
之所以叫硬同步,是因为TestAndSet()函数中的三条语句是由硬件保证同步的,即硬件保证这三条语句必须原子运行,中间不发生任何中断,如同一条语句。之所以这样保证,是因为函数体内本身就是一个criticalsection,在多线程程序中,如果在这几条语句中间被中断,也会有race condition发生。
TA贡献1815条经验 获得超10个赞
TestAndSet
一个执行单元要想访问被自旋锁保护的共享资源,必须先得到锁,在访问完共享资源后,必须释放锁。如果在获取自旋锁时,没有任何执行单元保持该锁,那么将立即得到锁;如果在获取自旋锁时锁已经有保持者,那么获取锁操作将自旋在那里,直到该自旋锁的保持者释放了锁。由此可以看出,自旋锁是一种比较低级的保护数据结构或代码片段的原始方式,这种锁可能存在两个问题:
死锁。试图递归地获得自旋锁必然会引起死锁:递归程序的持有实例在第二个实例循环,以试图获得相同自旋锁时,不会释放此自旋锁。在递归程序中使用自旋锁应遵守下列策略:递归程序决不能在持有自旋锁时调用它自己,也决不能在递归调用时试图获得相同的自旋锁。此外如果一个进程已经将资源锁定,那么,即使其它申请这个资源的进程不停地疯狂“自旋”,也无法获得资源,从而进入死循环。
过多占用cpu资源。如果不加限制,由于申请者一直在循环等待,因此自旋锁在锁定的时候,如果不成功,不会睡眠,会持续的尝试,单cpu的时候自旋锁会让其它process动不了. 因此,一般自旋锁实现会有一个参数限定最多持续尝试次数. 超出后, 自旋锁放弃当前time slice. 等下一次机会。
- 2 回答
- 0 关注
- 101 浏览
添加回答
举报