请教一下,获取spinlock时,为什么要将调用preempt_disable?

737 views
Skip to first unread message

胡杨树

unread,
Oct 18, 2010, 11:23:38 PM10/18/10
to linux-kernel
使用spinlock时,需要包含include/linux/spinlock.h, 这是一个顶层文件

#define spin_lock(lock) _spin_lock(lock)
_spin_lock的SMP版本在kernel/spinlock.c中实现,UP版本的include/linux/spinlock_up.h中实现


不管是SMP/UP,在调用spin_lock的时候为何要禁止内核抢占?
_______________________________________________
Linux 内核开发中文邮件列表
Linux-...@zh-kernel.org
http://zh-kernel.org/mailman/listinfo/linux-kernel
Linux 内核开发中文社区: http://zh-kernel.org

Li Yu

unread,
Oct 19, 2010, 12:15:58 AM10/19/10
to 胡杨树, linux-kernel

于 2010年10月19日 11:23, 胡杨树 写道:
> 使用spinlock时,需要包含include/linux/spinlock.h, 这是一个顶层文件
>
> #define spin_lock(lock) _spin_lock(lock)
> _spin_lock的SMP版本在kernel/spinlock.c中实现,UP版本的include/linux/spinlock_up.h中实现
>
>
> 不管是SMP/UP,在调用spin_lock的时候为何要禁止内核抢占?

为了让本处理器上的lock持有者可以有机会释放锁呗~

Yong Zhang

unread,
Oct 19, 2010, 12:40:40 AM10/19/10
to 胡杨树, linux-kernel
2010/10/19 胡杨树 <9140...@qq.com>:

> 使用spinlock时,需要包含include/linux/spinlock.h, 这是一个顶层文件
>
> #define spin_lock(lock)            _spin_lock(lock)
> _spin_lock的SMP版本在kernel/spinlock.c中实现,UP版本的include/linux/spinlock_up.h中实现
>
>
> 不管是SMP/UP,在调用spin_lock的时候为何要禁止内核抢占?

避免优先级反转。

Miao Xie

unread,
Oct 19, 2010, 2:44:09 AM10/19/10
to 胡杨树, linux-kernel
On Tue, 19 Oct 2010 11:23:38 +0800, 胡杨树 wrote:
> 使用spinlock时,需要包含include/linux/spinlock.h, 这是一个顶层文件
>
> #define spin_lock(lock) _spin_lock(lock)
> _spin_lock的SMP版本在kernel/spinlock.c中实现,UP版本的include/linux/spinlock_up.h中实现
>
>
> 不管是SMP/UP,在调用spin_lock的时候为何要禁止内核抢占?

我认为目的是为了不被调度出去。因为spin lock的设计初衷就是在段时间内进行轻量级加锁,
锁的争用者进行循环等待,而不调度出去,这样提高性能。

Li Yu

unread,
Oct 19, 2010, 3:35:22 AM10/19/10
to mi...@cn.fujitsu.com, linux-kernel

于 2010年10月19日 14:44, Miao Xie 写道:
> On Tue, 19 Oct 2010 11:23:38 +0800, 胡杨树 wrote:
>> 使用spinlock时,需要包含include/linux/spinlock.h, 这是一个顶层文件
>>
>> #define spin_lock(lock) _spin_lock(lock)
>> _spin_lock的SMP版本在kernel/spinlock.c中实现,UP版本的include/linux
>> /spinlock_up.h中实现
>>
>>
>> 不管是SMP/UP,在调用spin_lock的时候为何要禁止内核抢占?
>
> 我认为目的是为了不被调度出去。因为spin lock的设计初衷就是在段时间内进行
> 轻量级加锁,
> 锁的争用者进行循环等待,而不调度出去,这样提高性能。

+1

呵呵,刚才我看错了,以为是抢spinlock时~

Yinglin Luan

unread,
Oct 19, 2010, 4:31:44 AM10/19/10
to 胡杨树, linux-kernel
如果不禁止抢占,那么当更高优先级的process进入就绪队列时,就会抢占calling process,从而导致calling
process睡眠,这与设计spinlock的初衷是不符的,spinlock的本质是一种忙等待机制,而mutex才是睡眠等待机制。在获取spinlock时,即使该锁不可获得,也要“自旋”,而不是让出处理器。

--
Yinglin Luan
Best Regards

Changli Gao

unread,
Oct 19, 2010, 4:43:53 AM10/19/10
to Yinglin Luan, linux-kernel
2010/10/19 Yinglin Luan <syn...@gmail.com>:

> 如果不禁止抢占,那么当更高优先级的process进入就绪队列时,就会抢占calling process,从而导致calling
> process睡眠,这与设计spinlock的初衷是不符的,spinlock的本质是一种忙等待机制,而mutex才是睡眠等待机制。在获取spinlock时,即使该锁不可获得,也要“自旋”,而不是让出处理器。
>

所以,恰恰是这个自旋锁才会导致优先级翻转,rt-linux才要求有可以睡眠的自旋锁实现。


--
Regards,
Changli Gao(xia...@gmail.com)

胡杨树

unread,
Oct 19, 2010, 8:27:34 AM10/19/10
to Changli Gao, linux-kernel
忙了一天了,不好意思现在才回大家;
说说自己的体会,spinlock 本身是用来锁住critical section的。

如果进程A在内核态调用spin_lock时没有禁止内核抢占,那这个时候更高优先级的进程B获得处理器来执行,而这时进程B也需要获得这个spinlock,这时进程B就一直在那忙等。
如果没有比进程B更好优先级的进程来打断进程B的执行,那么进程B一直会耗尽自己的时间片,等到进程A获得处理器释放
spinlock后进程B才能得到执行;

在spinlock中禁止内核抢占后,就不会出先上面说的那种情况了,因为进程A获得spinlock后,内核这时出去非抢占的状态,进程A在内核态会一直执行下去,调度器不会切到其他进程中。







------------------ Original ------------------
From: "Changli Gao"<xia...@gmail.com>;
Date: Tue, Oct 19, 2010 04:43 PM
To: "Yinglin Luan"<syn...@gmail.com>;
Cc: "胡杨树"<9140...@qq.com>; "linux-kernel"<linux-...@zh-kernel.org>;
Subject: Re: 请教一下,获取spinlock时,为什么要将调用preempt_disable?

Américo Wang

unread,
Oct 19, 2010, 10:27:45 AM10/19/10
to Yinglin Luan, linux-kernel
On Tue, Oct 19, 2010 at 04:31:44PM +0800, Yinglin Luan wrote:
>如果不禁止抢占,那么当更高优先级的process进入就绪队列时,就会抢占calling process,从而导致calling
>process睡眠,这与设计spinlock的初衷是不符的,spinlock的本质是一种忙等待机制,而mutex才是睡眠等待机制。在获取spinlock时,即使该锁不可获得,也要“自旋”,而不是让出处理器。
>

+1

我觉得可以从两方面考虑这个问题:

1. spin_lock()本身不能睡眠,要么直接进去,要么处于忙等状态。
这就是Yinglin所言。

2. 持有spin_lock之后,必须保证不让一个以上的进程同时进入critical section,
让进去的进程一次执行完毕,让进不去的进程在spin。所以才会禁止抢占,否则
另外一个进程也有可能进去。在SMP上除了本CPU禁止抢占以外,还需要让
别的CPU上的进程进行spin,同时允许抢占。

--
Live like a child, think like the god.

胡杨树

unread,
Oct 19, 2010, 10:37:19 AM10/19/10
to wang cong, linux-kernel
>>>>获取spinlock时,即使该锁不可获得,也要“自旋”,而不是让出处理器。
这个不会一直自旋下去,该进程的时间片用完后,调度器会切入其它进程;


>>>> 2. 持有spin_lock之后,必须保证不让一个以上的进程同时进入critical section,
>>>>让进去的进程一次执行完毕,让进不去的进程在spin。所以才会禁止抢占,
恩,这个是对的。

>>>否则另外一个进程也有可能进去。在SMP上除了本CPU禁止抢占以外,还需要让
>>>别的CPU上的进程进行spin,同时允许抢占。
另外一个进程如何进入? spinlock中如果不禁止内核抢占,持有锁的进程A会被其它进程
B打断,B进程如果再想获得锁的话,它只能忙等,而不可能进入到spinlock保护的critical section中;





------------------ Original ------------------
From: "wang cong"<xiyou.w...@gmail.com>;
Date: Tue, Oct 19, 2010 10:27 PM
To: "Yinglin Luan"<syn...@gmail.com>;
Cc: "胡杨树"<9140...@qq.com>; "linux-kernel"<linux-...@zh-kernel.org>;
Subject: Re: 请教一下,获取spinlock时,为什么要将调用preempt_disable?


Américo Wang

unread,
Oct 19, 2010, 11:13:29 AM10/19/10
to 胡杨树, linux-kernel
On Tue, Oct 19, 2010 at 10:37:19PM +0800, 胡杨树 wrote:
>>>>> 2. 持有spin_lock之后,必须保证不让一个以上的进程同时进入critical section,
> >>>>让进去的进程一次执行完毕,让进不去的进程在spin。所以才会禁止抢占,
>恩,这个是对的。
>
>>>>否则另外一个进程也有可能进去。在SMP上除了本CPU禁止抢占以外,还需要让
>>>>别的CPU上的进程进行spin,同时允许抢占。
>另外一个进程如何进入? spinlock中如果不禁止内核抢占,持有锁的进程A会被其它进程
>B打断,B进程如果再想获得锁的话,它只能忙等,而不可能进入到spinlock保护的critical section中;
>

那样spin_lock保护的代码的原子性就得不到保证了。;-)

spin_lock(); //assume no preempt_disable
statement1;
<============ preempt
statement2;
spin_unlock();

虽然别的进程不能执行statement1和statement2。

胡杨树

unread,
Oct 19, 2010, 11:22:47 AM10/19/10
to wang cong, linux-kernel
>>>那样spin_lock保护的代码的原子性就得不到保证了。;-)
>>>spin_lock(); //assume no preempt_disable
>>>statement1;
>>> <============ preempt
>>>statement2;
>>>spin_unlock();
>>>虽然别的进程不能执行statement1和statement2。我理解spinlock保护的critical section是防止重入,进程在statement1和statement2之间还是可以被时钟中断打断的,即使如此,其它高优先级的进程也不能得到运行,因为spinlock已禁止内核抢占;
提供原子性保护的接口用spin_lock_irqsave这个可以实现,这个接口会保证statement1和statement2之间没有任何被其它任何代码打断;




------------------ Original ------------------
From: "wang cong"<xiyou.w...@gmail.com>;
Date: Tue, Oct 19, 2010 11:13 PM
To: "胡杨树"<9140...@qq.com>;
Cc: "wang cong"<xiyou.w...@gmail.com>; "linux-kernel"<linux-...@zh-kernel.org>;
Subject: Re: 请教一下,获取spinlock时,为什么要将调用preempt_disable?


Américo Wang

unread,
Oct 19, 2010, 11:33:32 AM10/19/10
to 胡杨树, linux-kernel
On Tue, Oct 19, 2010 at 11:22:47PM +0800, 胡杨树 wrote:
>提供原子性保护的接口用spin_lock_irqsave这个可以实现,这个接口会保证statement1和statement2之间没有任何被其它任何代码打断;
>

这个理解不对。spin_lock_irqsave()是为了防止和IRQ call path发生竞争,比如:

spin_lock();
statement1;
<====== interrupt!!
spin_lock(); <====== BUG
statement2;
spin_unlock();

spin_lock_bh()同理,只不过是softirq。

Changli Gao

unread,
Oct 19, 2010, 11:45:36 AM10/19/10
to Américo Wang, linux-kernel
2010/10/19 Américo Wang <xiyou.w...@gmail.com>:

> On Tue, Oct 19, 2010 at 11:22:47PM +0800, 胡杨树 wrote:
>>提供原子性保护的接口用spin_lock_irqsave这个可以实现,这个接口会保证statement1和statement2之间没有任何被其它任何代码打断;
>>
>
> 这个理解不对。spin_lock_irqsave()是为了防止和IRQ call path发生竞争,比如:
>

我认为胡的说法是对的,如果进程只有spinlock而没有关中断,难免会被cpu的IRQ所中断,耽搁过长时间。而你所举的例子只是发生在irq
handler或者是softirq中也有同一个的spinlock的情形。当然,进程之间共享变量的保护,spinlock就足够,没必要非得禁止中断。

--
Regards,
Changli Gao(xia...@gmail.com)

Américo Wang

unread,
Oct 19, 2010, 12:35:09 PM10/19/10
to Changli Gao, linux-kernel
On Tue, Oct 19, 2010 at 11:45:36PM +0800, Changli Gao wrote:
>2010/10/19 Américo Wang <xiyou.w...@gmail.com>:
>> On Tue, Oct 19, 2010 at 11:22:47PM +0800, 胡杨树 wrote:
>>>提供原子性保护的接口用spin_lock_irqsave这个可以实现,这个接口会保证statement1和statement2之间没有任何被其它任何代码打断;
>>>
>>
>> 这个理解不对。spin_lock_irqsave()是为了防止和IRQ call path发生竞争,比如:
>>
>
>我认为胡的说法是对的,如果进程只有spinlock而没有关中断,难免会被cpu的IRQ所中断,耽搁过长时间。而你所举的例子只是发生在irq
>handler或者是softirq中也有同一个的spinlock的情形。当然,进程之间共享变量的保护,spinlock就足够,没必要非得禁止中断。
>

如果必须关中断才能保证的话,那spin_lock()里就应该关了,
而不会再提供一个spin_lock_irqsave()接口,这个接口存在的目的就是
为了防止前面说的竞争。

所以,spin_lock()保证它保护的代码不被其它进程中断就够了,即我前面
提到的不涉及中断的原子性。

--
Live like a child, think like the god.

Américo Wang

unread,
Oct 19, 2010, 12:46:59 PM10/19/10
to Changli Gao, linux-kernel
2010/10/20 Américo Wang <xiyou.w...@gmail.com>:
>
> 所以,spin_lock()保证它保护的代码不被其它进程中断就够了,即我前面
> 提到的不涉及中断的原子性。

啊!其实spin_lock()没必要保证里面的代码不被其它进程中断,因为任何
其它地方读写spin_lock()里代码操作的数据的话也都应该加spin_lock()。

那这么看来spin_lock()在UP上禁止抢占只是为了防止Priority Inversion Problem了。
:-/

Changli Gao

unread,
Oct 19, 2010, 7:47:42 PM10/19/10
to Américo Wang, linux-kernel
2010/10/20 Américo Wang <xiyou.w...@gmail.com>:
>
> 那这么看来spin_lock()在UP上禁止抢占只是为了防止Priority Inversion Problem了。
> :-/
>

也不能这么说,前面有人已经分析过了,禁止抢占会导致高优先级进程得不到及时调度,降低了系统的实时性。而优先级反转应该也不会出现,因为spin_unlock的时候,会调度最高优先级程序运行。

spinlock在不可抢占UP系统上展开为空,你试想一下,如果在可抢占UP系统上,也展开为空,而不是禁止抢占,它还能起到保护共享数据的作用么?

--
Regards,
Changli Gao(xia...@gmail.com)

ZHANG XIAO-MING-MND637

unread,
Oct 19, 2010, 8:59:52 PM10/19/10
to Américo Wang, linux-kernel
Américo Wang wrote:
> 2010/10/20 Américo Wang <xiyou.w...@gmail.com>:
>>
>> ?,spin_lock()保证它保护的代码不被其它进程中断就够了,即我前面
>> 提到的不涉及中断的原子??
>
> 啊!其实spin_lock()没必要保证里面的代码不被其它进程中断,因为任?
> 其它地方读写spin_lock()里代码操作的数据的话也都应该加spin_lock()?
>
> 那这么看来spin_lock()在UP上禁止抢占只是为了防止Priority Inversion Problem了?
> :-/
> _____

我有个问题,考虑这种情况?

对同?PU?

spin_lock()
....

(内核抢占,切换到另一个进?

spin_lock()
....

如果不perrmpt_disable(), 那么会有这种情况发生吗?如果有那后果是什么?

__________________________________________
> Linux 内核?中文邮件列表
> Linux-...@zh-kernel.org
> http://zh-kernel.org/mailman/listinfo/linux-kernel
> Linux 内核?中文社区?http://zh-kernel.org

Liu Jianing

unread,
Oct 20, 2010, 6:17:52 AM10/20/10
to Américo Wang, linux-kernel
spin_lock_irqsave()不是为了保存关闭中断前中断许可标志的么?防止spin_lock
之前中断都是关闭的。

不是很懂
On Wed, 2010-10-20 at 00:35 +0800, Américo Wang wrote:
> spin_lock_irqsave()
--
Liu Jianing <spong...@gmail.com>
Key Laboratory of Computer System and Architecture, CAS

ZHANG XIAO-MING-MND637

unread,
Oct 19, 2010, 10:30:36 PM10/19/10
to Américo Wang, linux-kernel
ZHANG XIAO-MING-MND637 wrote:
> Américo Wang wrote:
>> 2010/10/20 Américo Wang <xiyou.w...@gmail.com>:
>>>
>>> ?,spin_lock()保证它保护的代码不被其它进程中断就够了,即我前面
>>> 提到的不涉及中断的原子??
>>
>> 啊!其实spin_lock()没必要保证里面的代码不被其它进程中断,因为任?
>> 其它地方读写spin_lock()里代码操作的数据的话也都应该加spin_lock()?
>>
>> 那这么看来spin_lock()在UP上禁止抢占只是为了防止Priority Inversion Problem了?
>> :-/
>> _____
>
> 我有个问题,考虑这种情况?
>
> 对同?PU?
>
> spin_lock()
> ....
>
> (内核抢占,切换到另一个进?
>
> spin_lock()
> ....
>
> 如果不perrmpt_disable(), 那么会有这种情况发生吗?如果有那后果是什么?
>
Sorry I get a problem in my Thunderbird's character encoding.
Try GB2312:

我有个问题,考虑这种情况:

对同一CPU:

spin_lock()
....

(内核抢占,切换到另一个进程)

Américo Wang

unread,
Oct 19, 2010, 11:23:13 PM10/19/10
to Changli Gao, linux-kernel
On Wed, Oct 20, 2010 at 07:47:42AM +0800, Changli Gao wrote:
>2010/10/20 Américo Wang <xiyou.w...@gmail.com>:
>>
>> 那这么看来spin_lock()在UP上禁止抢占只是为了防止Priority Inversion Problem了。
>> :-/
>>
>
>也不能这么说,前面有人已经分析过了,禁止抢占会导致高优先级进程得不到及时调度,降低了系统的实时性。而优先级反转应该也不会出现,因为spin_unlock的时候,会调度最高优先级程序运行。

你在说使用spin_lock的缺点?我在说spin_lock的实现,你跑题了。
至于你说的问题,它的实现就决定了如此。;-) 所以你还有其它很多选择,
mutex,semaphore,rwlock,rwsem,RCU。


>
>spinlock在不可抢占UP系统上展开为空,你试想一下,如果在可抢占UP系统上,也展开为空,而不是禁止抢占,它还能起到保护共享数据的作用么?
>

可以的。如果不考虑 priority inversion,我们完全可以:

for(;;) {
if (is_not_locked()){
lock_it();
break;
} else
spin();
}

这样也可以保护。但是Priority Inversion导致的死锁就会发生。

实际上,不看抢占的话,上面的伪代码正是spin_lock在SMP上的实现。
在SMP上如果其它CPU在spin的话它还要打开抢占,就是为了降低你说的实时性。
所以就成了:

for(::) {
preempt_disable();
if (try_lock())
break;
preempt_enable();
check_and_spin();

Adam Jiang

unread,
Oct 20, 2010, 12:33:30 AM10/20/10
to ZHANG XIAO-MING-MND637, linux-kernel
On Wed, Oct 20, 2010 at 10:30:36AM +0800, ZHANG XIAO-MING-MND637 wrote:
> ZHANG XIAO-MING-MND637 wrote:
> > Américo Wang wrote:
> >> 2010/10/20 Américo Wang <xiyou.w...@gmail.com>:
> >>>
> >>> ?,spin_lock()保证它保护的代码不被其它进程中断就够了,即我前面
> >>> 提到的不涉及中断的原子??
> >>
> >> 啊!其实spin_lock()没必要保证里面的代码不被其它进程中断,因为任?
> >> 其它地方读写spin_lock()里代码操作的数据的话也都应该加spin_lock()?
> >>
> >> 那这么看来spin_lock()在UP上禁止抢占只是为了防止Priority Inversion Problem了?
> >> :-/
> >> _____
> Sorry I get a problem in my Thunderbird's character encoding.
> Try GB2312:
>
> 我有个问题,考虑这种情况:
>
> 对同一CPU:
> spin_lock()
> ....
> (内核抢占,切换到另一个进程)
> spin_lock()
> ....
>
> 如果不perrmpt_disable(), 那么会有这种情况发生吗?如果有那后果是什么?

后果就是前面几位提到的priority inversion。

假设有进程A,B,C;优先级A>B>C;A,C进程都需要临界区数据;而B不需要;

如果某个条件下,A进程得到机会执行,但C却持有它需要的锁,所以A虽然得到CPU
但是却只能等待;CPU上又回放回C;接着B试图执行,它可以将C挤出去,因为它的
优先级高于C,而且它也不需要C持有的锁;B执行结束后,C又回到CPU上继续执行
,直到它结束并且放开锁,A才有可能得到锁以便完成任务。那么最终结果就是,B
最先完成,接着是C,最后是A。这个结果就与他们原来定义的优先级不同了,优先
级最高的任务反而最后完成。

如果这里禁止抢占,那么调度就不需要考虑优先级,仅仅依赖于是否可以获得锁。
当C持有锁的时候,A会等待;而B不会被调度进来,因为优先级判断已经失效了。
只能等C执行结束,才有机会调度A或者B。这看起来就是spin_lock想要的效果。但
是这种情况里,就没有什么优先级的概念了,系统的实时性——也就是按照优先级调
度的能力——就无法得到保障了。

/大头阿当

Adam Jiang

unread,
Oct 20, 2010, 12:41:03 AM10/20/10
to Américo Wang, linux-kernel
On Wed, Oct 20, 2010 at 11:23:13AM +0800, Américo Wang wrote:
> On Wed, Oct 20, 2010 at 07:47:42AM +0800, Changli Gao wrote:
> >2010/10/20 Américo Wang <xiyou.w...@gmail.com>:
> >>
> >> 那这么看来spin_lock()在UP上禁止抢占只是为了防止Priority Inversion
> >> Problem了。:-/
> >
> >也不能这么说,前面有人已经分析过了,禁止抢占会导致高优先级进程得不到
> >及时调度,降低了系统的实时性。而优先级反转应该也不会出现,因为
> >spin_unlock的时候,会调度最高优先级程序运行。
>
> 你在说使用spin_lock的缺点?我在说spin_lock的实现,你跑题了。
> 至于你说的问题,它的实现就决定了如此。;-) 所以你还有其它很多选择,
> mutex,semaphore,rwlock,rwsem,RCU。
> >
> >spinlock在不可抢占UP系统上展开为空,你试想一下,如果在可抢占UP系统上
> >,也展开为空,而不是禁止抢占,它还能起到保护共享数据的作用么?
> >
>
> 可以的。如果不考虑 priority inversion,我们完全可以:
>
> for(;;) {
> if (is_not_locked()){
> lock_it();
> break;
> } else
> spin();
> }
>
> 这样也可以保护。但是Priority Inversion导致的死锁就会发生。

Priority inversion并非导致死锁,而是导致高优先级任务反而比低优先级任务完
成的更晚,也就是发生了反转。如果发生死锁的话,“保护临界区”这个任务也就没
有什么意义了。但事实情况是,虽然优先级翻转了,共享数据的访问却没有被破坏
,所以,正如你说的“这样也可以保护”。这句话只对了一半,right? :)

> 实际上,不看抢占的话,上面的伪代码正是spin_lock在SMP上的实现。在SMP上
> 如果其它CPU在spin的话它还要打开抢占,就是为了降低你说的实时性。

打开抢占却降低了实时性?何解?

/阿当

Américo Wang

unread,
Oct 20, 2010, 1:00:49 AM10/20/10
to Adam Jiang, linux-kernel
On Wed, Oct 20, 2010 at 01:41:03PM +0900, Adam Jiang wrote:
>> >spinlock在不可抢占UP系统上展开为空,你试想一下,如果在可抢占UP系统上
>> >,也展开为空,而不是禁止抢占,它还能起到保护共享数据的作用么?
>> >
>>
>> 可以的。如果不考虑 priority inversion,我们完全可以:
>>
>> for(;;) {
>> if (is_not_locked()){
>> lock_it();
>> break;
>> } else
>> spin();
>> }
>>
>> 这样也可以保护。但是Priority Inversion导致的死锁就会发生。
>
>Priority inversion并非导致死锁,而是导致高优先级任务反而比低优先级任务完
>成的更晚,也就是发生了反转。如果发生死锁的话,“保护临界区”这个任务也就没
>有什么意义了。但事实情况是,虽然优先级翻转了,共享数据的访问却没有被破坏


抛除死锁不死锁不谈(会在另一封邮件中回复),这正是我的观点,Changli认为
不禁止抢占就无法保护数据,我认为可以。


>,所以,正如你说的“这样也可以保护”。这句话只对了一半,right? :)
>

那一句后面的“但是”很不明显嘛?:)


>> 实际上,不看抢占的话,上面的伪代码正是spin_lock在SMP上的实现。在SMP上
>> 如果其它CPU在spin的话它还要打开抢占,就是为了降低你说的实时性。
>
>打开抢占却降低了实时性?何解?


漏了“防止”一词。。。

Américo Wang

unread,
Oct 20, 2010, 1:07:34 AM10/20/10
to Adam Jiang, linux-kernel

你忘了spin_lock里是忙等而非等待了,所以A不会让出CPU。

所以情况就是A占有CPU却在执行无用的忙等操作,得不锁,持有锁的进程C
因为优先级低无法去释放锁,“死锁”就形成了,只要调度器没有打破这种局面。

Changli Gao

unread,
Oct 20, 2010, 1:02:48 AM10/20/10
to Américo Wang, linux-kernel
2010/10/20 Américo Wang <xiyou.w...@gmail.com>:

>
> 抛除死锁不死锁不谈(会在另一封邮件中回复),这正是我的观点,Changli认为
> 不禁止抢占就无法保护数据,我认为可以。
>

如果是支持内核抢占的UP,在spinlock锁住的临界区如果不关闭抢占,那么spinlock就应该展开为空,恰巧在临界区中有被抢占,并且抢占进程也要访问前面的spinlock保护的数据,不就发生竞态了。


--
Regards,
Changli Gao(xia...@gmail.com)

Américo Wang

unread,
Oct 20, 2010, 1:13:52 AM10/20/10
to Changli Gao, linux-kernel
On Wed, Oct 20, 2010 at 01:02:48PM +0800, Changli Gao wrote:
>2010/10/20 Américo Wang <xiyou.w...@gmail.com>:
>>
>> 抛除死锁不死锁不谈(会在另一封邮件中回复),这正是我的观点,Changli认为
>> 不禁止抢占就无法保护数据,我认为可以。
>>
>
>如果是支持内核抢占的UP,在spinlock锁住的临界区如果不关闭抢占,那么spinlock就应该展开为空,恰巧在临界区中有被抢占,并且抢占进程也要访问前面的spinlock保护的数据,不就发生竞态了。
>

请问展开都为空了,如何去锁住临界区呢?

spin_lock之所以在非抢占的UP上展开为空,是因为根本就没有进程进行竞争,
所以不需要锁。

Adam Jiang

unread,
Oct 20, 2010, 1:11:12 AM10/20/10
to Américo Wang, linux-kernel

...对。

> 所以情况就是A占有CPU却在执行无用的忙等操作,得不锁,持有锁的进程C
> 因为优先级低无法去释放锁,“死锁”就形成了,只要调度器没有打破这种局面。

也就是说,假设系统中只有这三个进程,或者A就是系统中最高优先级,那么这个
时候事实上就只有A能在这里做无用功了。其结论就是,如果没有preempt_disable
,那么,spin_lock干脆会导致死锁,就不要谈保护临界区了。

/阿当

Adam Jiang

unread,
Oct 20, 2010, 1:12:33 AM10/20/10
to Américo Wang, linux-kernel

所以,如果不是spin_lock而是semaphore或者mutex,这里会发生优先级翻转。
spin_lock的情况特殊,根本没有优先级翻转什么事情。

/阿当

Changli Gao

unread,
Oct 20, 2010, 1:24:44 AM10/20/10
to Américo Wang, linux-kernel
2010/10/20 Américo Wang <xiyou.w...@gmail.com>:

>
> 请问展开都为空了,如何去锁住临界区呢?
>
> spin_lock之所以在非抢占的UP上展开为空,是因为根本就没有进程进行竞争,
> 所以不需要锁。
>

咱么不是讨论为什么抢占UP上的spinlock要禁止抢占么。我的假设是如果不禁止抢占,spinlock不就要和非抢占UP一样为空了。可是展开为空是不行的,因为有其它进程参与竞争啊。

--
Regards,
Changli Gao(xia...@gmail.com)

Américo Wang

unread,
Oct 20, 2010, 1:34:15 AM10/20/10
to Adam Jiang, linux-kernel
On Wed, Oct 20, 2010 at 02:12:33PM +0900, Adam Jiang wrote:
>> >
>> >后果就是前面几位提到的priority inversion。
>> >
>> >假设有进程A,B,C;优先级A>B>C;A,C进程都需要临界区数据;而B不需要;
>> >
>> >如果某个条件下,A进程得到机会执行,但C却持有它需要的锁,所以A虽然得到CPU
>> >但是却只能等待;CPU上又回放回C;接着B试图执行,它可以将C挤出去,因为它的
>>
>> 你忘了spin_lock里是忙等而非等待了,所以A不会让出CPU。
>
>所以,如果不是spin_lock而是semaphore或者mutex,这里会发生优先级翻转。
>spin_lock的情况特殊,根本没有优先级翻转什么事情。
>

看你到底把不把这种情况叫做优先级翻转了。

我觉得没任何问题,持有锁的就是应该优先执行,没有锁的进程优先级就应该低,
翻转了。;-)

Changli Gao

unread,
Oct 20, 2010, 1:40:41 AM10/20/10
to Adam Jiang, linux-kernel
2010/10/20 Adam Jiang <jiang...@gmail.com>:

>
> 后果就是前面几位提到的priority inversion。
>
> 假设有进程A,B,C;优先级A>B>C;A,C进程都需要临界区数据;而B不需要;
>
> 如果某个条件下,A进程得到机会执行,但C却持有它需要的锁,所以A虽然得到CPU
> 但是却只能等待;CPU上又回放回C;接着B试图执行,它可以将C挤出去,因为它的
> 优先级高于C,而且它也不需要C持有的锁;B执行结束后,C又回到CPU上继续执行
> ,直到它结束并且放开锁,A才有可能得到锁以便完成任务。那么最终结果就是,B
> 最先完成,接着是C,最后是A。这个结果就与他们原来定义的优先级不同了,优先
> 级最高的任务反而最后完成。

我觉得你理解的是对的。合理的执行顺序应该是C A B。

>
> 如果这里禁止抢占,那么调度就不需要考虑优先级,仅仅依赖于是否可以获得锁。
> 当C持有锁的时候,A会等待;而B不会被调度进来,因为优先级判断已经失效了。
> 只能等C执行结束,才有机会调度A或者B。这看起来就是spin_lock想要的效果。但
> 是这种情况里,就没有什么优先级的概念了,系统的实时性――也就是按照优先级调
> 度的能力――就无法得到保障了。
>

禁止抢占正是防止优先级反转的一个方法:优先级天花板(http://baike.baidu.com/view/2422471.html?fromTaglist)。spin
unlock的时候会选择最高优先级进程执行,所以上例的执行顺序应该是C A B.

--
Regards,
Changli Gao(xia...@gmail.com)

Américo Wang

unread,
Oct 20, 2010, 1:55:39 AM10/20/10
to Changli Gao, linux-kernel
On Wed, Oct 20, 2010 at 01:24:44PM +0800, Changli Gao wrote:
>2010/10/20 Américo Wang <xiyou.w...@gmail.com>:
>>
>> 请问展开都为空了,如何去锁住临界区呢?
>>
>> spin_lock之所以在非抢占的UP上展开为空,是因为根本就没有进程进行竞争,
>> 所以不需要锁。
>>
>
>咱么不是讨论为什么抢占UP上的spinlock要禁止抢占么。我的假设是如果不禁止抢占,spinlock不就要和非抢占UP一样为空了。可是展开为空是不行的,因为有其它进程参与竞争啊。
>

你理解错了,我们讨论的不是在现有的linux内核实现上去掉禁止抢占,
而是我们为什么一定要UP禁止抢占。

Changli Gao

unread,
Oct 20, 2010, 1:55:19 AM10/20/10
to Américo Wang, linux-kernel
2010/10/20 Américo Wang <xiyou.w...@gmail.com>:

> On Wed, Oct 20, 2010 at 01:24:44PM +0800, Changli Gao wrote:
>>2010/10/20 Américo Wang <xiyou.w...@gmail.com>:
>>>
>>> 请问展开都为空了,如何去锁住临界区呢?
>>>
>>> spin_lock之所以在非抢占的UP上展开为空,是因为根本就没有进程进行竞争,
>>> 所以不需要锁。
>>>
>>
>>咱么不是讨论为什么抢占UP上的spinlock要禁止抢占么。我的假设是如果不禁止抢占,spinlock不就要和非抢占UP一样为空了。可是展开为空是不行的,因为有其它进程参与竞争啊。
>>
>
> 你理解错了,我们讨论的不是在现有的linux内核实现上去掉禁止抢占,
> 而是我们为什么一定要UP禁止抢占。
>
>

不是一会事么?我只是从反面论证,如果不禁止抢占会怎么样,以此来证明,禁止抢占是必须的。我逻辑有问题么? :)

--
Regards,
Changli Gao(xia...@gmail.com)

Américo Wang

unread,
Oct 20, 2010, 2:09:32 AM10/20/10
to Changli Gao, linux-kernel
On Wed, Oct 20, 2010 at 01:55:19PM +0800, Changli Gao wrote:
>2010/10/20 Américo Wang <xiyou.w...@gmail.com>:
>> On Wed, Oct 20, 2010 at 01:24:44PM +0800, Changli Gao wrote:
>>>2010/10/20 Américo Wang <xiyou.w...@gmail.com>:
>>>>
>>>> 请问展开都为空了,如何去锁住临界区呢?
>>>>
>>>> spin_lock之所以在非抢占的UP上展开为空,是因为根本就没有进程进行竞争,
>>>> 所以不需要锁。
>>>>
>>>
>>>咱么不是讨论为什么抢占UP上的spinlock要禁止抢占么。我的假设是如果不禁止抢占,spinlock不就要和非抢占UP一样为空了。可是展开为空是不行的,因为有其它进程参与竞争啊。
>>>
>>
>> 你理解错了,我们讨论的不是在现有的linux内核实现上去掉禁止抢占,
>> 而是我们为什么一定要UP禁止抢占。
>>
>>
>
>不是一会事么?我只是从反面论证,如果不禁止抢占会怎么样,以此来证明,禁止抢占是必须的。我逻辑有问题么? :)
>

有的,请参考我之前一封邮件中的伪代码。;)

Adam Jiang

unread,
Oct 20, 2010, 2:04:22 AM10/20/10
to Changli Gao, linux-kernel
On Wed, Oct 20, 2010 at 01:55:19PM +0800, Changli Gao wrote:
> 2010/10/20 Américo Wang <xiyou.w...@gmail.com>:
> > On Wed, Oct 20, 2010 at 01:24:44PM +0800, Changli Gao wrote:
> >>2010/10/20 Américo Wang <xiyou.w...@gmail.com>:
> >>>
> >>> 请问展开都为空了,如何去锁住临界区呢?
> >>>
> >>> spin_lock之所以在非抢占的UP上展开为空,是因为根本就没有进程进行竞争,
> >>> 所以不需要锁。
> >>>
> >>
> >>咱么不是讨论为什么抢占UP上的spinlock要禁止抢占么。我的假设是如果不禁
> >>止抢占,spinlock不就要和非抢占UP一样为空了。可是展开为空是不行的,因
> >>为有其它进程参与竞争啊。
> >>
> >
> > 你理解错了,我们讨论的不是在现有的linux内核实现上去掉禁止抢占,
> > 而是我们为什么一定要UP禁止抢占。
> >
> >
>
> 不是一会事么?我只是从反面论证,如果不禁止抢占会怎么样,以此来证明,禁
> 止抢占是必须的。我逻辑有问题么? :)

没有问题,反正我理解了,^_^。

其实两位说的是一个硬币的两面,是一回事。结论是,spin_lock的时候调用
preempt_disable是必须的(内核代码会处理不同情况的抢占)。

最后一个疑问——这个是我读代码不熟悉造成,见谅,Wang和你都提到现有实现会将
持有spinlock的那个进程设置为最高优先级,也就是采用priority ceiling的做法
来避免发生“优先级翻转”或者“忙等”,能否指出具体相关的代码,我想看看。谢谢

/阿当

Américo Wang

unread,
Oct 20, 2010, 2:15:26 AM10/20/10
to Adam Jiang, linux-kernel
On Wed, Oct 20, 2010 at 03:04:22PM +0900, Adam Jiang wrote:
>
>最后一个疑问——这个是我读代码不熟悉造成,见谅,Wang和你都提到现有实现会将
>持有spinlock的那个进程设置为最高优先级,也就是采用priority ceiling的做法
>来避免发生“优先级翻转”或者“忙等”,能否指出具体相关的代码,我想看看。谢谢

你不认为禁止抢占就等同于把该进程以最高的优先级运行嘛?;)

Changli Gao

unread,
Oct 20, 2010, 2:11:14 AM10/20/10
to Adam Jiang, linux-kernel
2010/10/20 Adam Jiang <jiang...@gmail.com>:

> 最后一个疑问――这个是我读代码不熟悉造成,见谅,Wang和你都提到现有实现会将
> 持有spinlock的那个进程设置为最高优先级,也就是采用priority ceiling的做法
> 来避免发生“优先级翻转”或者“忙等”,能否指出具体相关的代码,我想看看。谢谢
> 。
>

禁止了抢占也就锁定了调度,相当于设定当前进程为最高优先级。不知道mutex当前是不是有优先级继承的特性,你可以看看。

Américo Wang

unread,
Oct 20, 2010, 2:20:33 AM10/20/10
to Changli Gao, linux-kernel
On Wed, Oct 20, 2010 at 02:11:14PM +0800, Changli Gao wrote:
>2010/10/20 Adam Jiang <jiang...@gmail.com>:
>> 最后一个疑问――这个是我读代码不熟悉造成,见谅,Wang和你都提到现有实现会将
>> 持有spinlock的那个进程设置为最高优先级,也就是采用priority ceiling的做法
>> 来避免发生“优先级翻转”或者“忙等”,能否指出具体相关的代码,我想看看。谢谢
>> 。
>>
>
>禁止了抢占也就锁定了调度,相当于设定当前进程为最高优先级。不知道mutex当前是不是有优先级继承的特性,你可以看看。
>

Documentation/rt-mutex*.txt

Adam Jiang

unread,
Oct 20, 2010, 2:23:19 AM10/20/10
to Américo Wang, linux-kernel
On Wed, Oct 20, 2010 at 02:15:26PM +0800, Américo Wang wrote:
> On Wed, Oct 20, 2010 at 03:04:22PM +0900, Adam Jiang wrote:
> >
> >最后一个疑问——这个是我读代码不熟悉造成,见谅,Wang和你都提到现有实现会将
> >持有spinlock的那个进程设置为最高优先级,也就是采用priority ceiling的做法
> >来避免发生“优先级翻转”或者“忙等”,能否指出具体相关的代码,我想看看。谢谢
>
> 你不认为禁止抢占就等同于把该进程以最高的优先级运行嘛?;)

从逻辑上说,是这样,因为禁止后就只有唯一一个优先级。

两位提到这个的时候,我以为是将上例中的C设置为系统中的最高优先级,而依然
保持其他进程优先级不变的做法。

/阿当

Adam Jiang

unread,
Oct 20, 2010, 2:42:24 AM10/20/10
to Américo Wang, linux-kernel
On Wed, Oct 20, 2010 at 01:13:52PM +0800, Américo Wang wrote:
> On Wed, Oct 20, 2010 at 01:02:48PM +0800, Changli Gao wrote:
> >2010/10/20 Américo Wang <xiyou.w...@gmail.com>:
> >>
> >> 抛除死锁不死锁不谈(会在另一封邮件中回复),这正是我的观点,Changli认为
> >> 不禁止抢占就无法保护数据,我认为可以。
> >>
> >
> >如果是支持内核抢占的UP,在spinlock锁住的临界区如果不关闭抢占,那么
> >spinlock就应该展开为空,恰巧在临界区中有被抢占,并且抢占进程也要访问
> >前面的spinlock保护的数据,不就发生竞态了。
> >
>
> 请问展开都为空了,如何去锁住临界区呢?
>
> spin_lock之所以在非抢占的UP上展开为空,是因为根本就没有进程进行竞争,
> 所以不需要锁。

你这这个说法是正确的。反过来说,如果在支持抢占的UP上将spinlock展开为空的
话,临界区就得不到保护。如果把前面的例子拿到这种情况下,进程C会直接被A挤
出去,同时也失去对临界区的保护。right?

但是Gao这个说法也是对的,与你的意思一样?逻辑似乎没错吧。如果有错,请明
确地讲一讲。

/阿当

张楠

unread,
Oct 23, 2010, 5:11:01 AM10/23/10
to Adam Jiang, Linux-...@zh-kernel.org

At 2010-10-20 13:11:12,"Adam Jiang" <jiang...@gmail.com> wrote: >On Wed, Oct 20, 2010 at 01:07:34PM +0800, Américo Wang wrote: >> On Wed, Oct 20, 2010 at 01:33:30PM +0900, Adam Jiang wrote: >> >On Wed, Oct 20, 2010 at 10:30:36AM +0800, ZHANG XIAO-MING-MND637 wrote: >> >> ZHANG XIAO-MING-MND637 wrote: >> >> > Américo Wang wrote: >> >> >> 2010/10/20 Américo Wang <xiyou.w...@gmail.com>: >> >> >>> >> >> >>> ?,spin_lock()保证它保护的代码不被其它进程中断就够了,即我前面 >> >> >>> 提到的不涉及中断的原子?? >> >> >> >> >> >> 啊!其实spin_lock()没必要保证里面的代码不被其它进程中断,因为任? >> >> >> 其它地方读写spin_lock()里代码操作的数据的话也都应该加spin_lock()? >> >> >> >> >> >> 那这么看来spin_lock()在UP上禁止抢占只是为了防止Priority Inversion Problem了? >> >> >> :-/ >> >> >> _____ >> >> Sorry I get a problem in my Thunderbird's character encoding. >> >> Try GB2312: >> >> >> >> 我有个问题,考虑这种情况: >> >> >> >> 对同一CPU: >> >> spin_lock() >> >> .... >> >> (内核抢占,切换到另一个进程) >> >> spin_lock() >> >> .... >> >> >> >> 如果不perrmpt_disable(), 那么会有这种情况发生吗?如果有那后果是什么? >> > >> >后果就是前面几位提到的priority inversion。 >> > >> >假设有进程A,B,C;优先级A>B>C;A,C进程都需要临界区数据;而B不需要; >> > >> >如果某个条件下,A进程得到机会执行,但C却持有它需要的锁,所以A虽然得到CPU >> >但是却只能等待;CPU上又回放回C;接着B试图执行,它可以将C挤出去,因为它的 >> >> 你忘了spin_lock里是忙等而非等待了,所以A不会让出CPU。 > >...对。 > >> 所以情况就是A占有CPU却在执行无用的忙等操作,得不锁,持有锁的进程C >> 因为优先级低无法去释放锁,“死锁”就形成了,只要调度器没有打破这种局面。 > >也就是说,假设系统中只有这三个进程,或者A就是系统中最高优先级,那么这个 >时候事实上就只有A能在这里做无用功了。其结论就是,如果没有preempt_disable >,那么,spin_lock干脆会导致死锁,就不要谈保护临界区了。 > >/阿当 >_______________________________________________ >Linux 内核开发中文邮件列表 >Linux-...@zh-kernel.org >http://zh-kernel.org/mailman/listinfo/linux-kernel >Linux 内核开发中文社区: http://zh-kernel.org

我认为这种情况严格的说不能叫死锁,而是饥饿现象。如果调度算法只满足高优先级的进程,低优先级进程会一直处于饥饿状态。但是Linux内核的调度机制能适当的照顾低优先级进程,使其有机会执行。
所以Preempt_disable在Linux系统中不是必须的(除非存在RealTime进程,这样获得SpinLock并且被抢占的低优先级进程就会一直处于饥饿状态)。Spinlock适用的场合是短时间处于临界区的情况,如果没有preempt disable,低优先级进程会频繁被高优先级进程抢占,这样反而使系统效率降低,违背Spinlock的设计初衷。

Reply all
Reply to author
Forward
0 new messages