免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 9354 | 回复: 21
打印 上一主题 下一主题

自旋锁 可抢占内核中使用自旋锁跟使用信号量有什么区别? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-06-02 18:20 |只看该作者 |倒序浏览
自旋锁:书上说在单CPU,可抢占式内核中,自旋锁还是有用的,但是这个时候还是会发送进程上下文的切换,这个跟信号量又有什么区别呢。





自旋锁:书上说这样使用:如果进程申请获得自旋锁不成功,便一直忙等待,知道可以成功获得自旋锁为止。

如果是在SMP上,这个很好理解。但是在单CPU上,如果在忙等待的进程不放弃CPU,持有该锁的进程怎么会有机会释放该锁呢,所以后面书上讲在单CPU上自旋锁的加锁操作是空操作。但是在内核可抢占的操作系统里,自旋锁又是可用的,既然内核都可以抢占了,那就是别的进程获得了CPU,这样还是发生了进程上下文的切换,这个时候跟信号量又有什么区别了,不是很理解。

论坛徽章:
0
2 [报告]
发表于 2010-06-02 19:04 |只看该作者
最新理解:

在单处理器中,自旋锁的工作仅仅是禁止内核抢占。在内核代码中,如果禁止内核抢占,内核会一直运行下去,知道它主动放弃CPU。也就是说这个时候不会发生进程切换。能够阻止该内核代码运行的就只有中断了,如果在中断中也申请同样的自旋锁就会发送死锁,所以也有一些形式的自旋锁是要禁止中断的。

我对自旋锁的理解就是:保证在内核代码中对一些数据的访问是原子进行的。

论坛徽章:
0
3 [报告]
发表于 2010-06-02 19:09 |只看该作者
那么自旋锁为什么不能被阻塞呢

论坛徽章:
0
4 [报告]
发表于 2010-06-02 20:54 |只看该作者
回复 3# zjh_larm


    还是自问自答。

关键问题是 申请自选锁后,内核是被禁止抢占的。

如果进程A在内核态下拥有自旋锁,被阻塞后,被调度的另外一个进程B也执行到同样的一段内核代码,申请自旋锁,但是由于进程A并没有释放该锁,所以B会一直自旋等待,同时内核被禁止抢占,也就是说进程B会一直自旋,不会让出处理器。

论坛徽章:
0
5 [报告]
发表于 2010-06-02 21:00 |只看该作者
同时又考虑到一个问题。

既然在单处理器上面,使用自旋锁就是为了禁止内核抢占,那么一个中断上下文和进程上下文之间又该如何做互斥与同步呢?

我的想法是:在中断上下文中不做处理,而在进程上下文(这里指的是内核态)中调用的是spin_lock_irqsave、spin_unlock_irqrestore这一对函数,因为这对函数禁止了中断。在进程上下文在处理临界区数据的时候,不必担心中断的发生。同时进程也不用担心会被抢占,会很快的完成处理。

论坛徽章:
0
6 [报告]
发表于 2010-06-04 21:48 |只看该作者
俺也是新手,不太懂。

也许这问题太简单吧。。。建议去CSDN问,至少会有人回答你,不至于自问自答。
俺发现,新手的问题,CU里高手们大部分是根本不鸟你的
俺以前也发过几个贴(不是这个号),没一个鸟俺。。。后来就改了,有什么问题都是去CSDN问,在CU里看一些精华的讨论

论坛徽章:
0
7 [报告]
发表于 2010-06-04 22:04 |只看该作者
正在学习LKD,刚好看到地九章内核同步。
说一点我的理解阿。有不对的地方,欢迎拍砖。

1.但是在单CPU上,如果在忙等待的进程不放弃CPU,持有该锁的进程怎么会有机会释放该锁呢
我的理解是:申请自旋锁失败后,不断忙循环等待,直到该进程的时间片用完,时间片用完,就必须切换进程了。

2.但是在内核可抢占的操作系统里,自旋锁又是可用的
为了支持内核抢占,每个进程的thread_info引入了preempt_count计数器。该计数器初始值为0,每当使用锁的时候值加1,释放锁的时候值减1。当该值为0时,内核就可以抢占。
所以,如果你使用了自旋锁,那么preempt_count的值就不为0,此时不允许内核抢占。

3.如果进程A在内核态下拥有自旋锁,被阻塞后,被调度的另外一个进程B也执行到同样的一段内核代码,申请自旋锁,但是由于进程A并没有释放该锁,所以B会一直自旋等待,同时内核被禁止抢占,也就是说进程B会一直自旋,不会让出处理器。
我的理解:既然是进程,时间片到了就切换进程。

4.那么一个中断上下文和进程上下文之间又该如何做互斥与同步呢
ISR与下半部都会抢占进程上下文,ISR还会抢占下半部,所以:
1>进程上下文与ISR:若共享数据,则在进程上下文中加锁的同时还要禁止本地中断。
2>进程上下文与下半部:若共享数据,则在进程上下文中加锁的同时还要禁止下半部执行。
3>ISR与下半部:若共享数据,则在下半部中加锁的同时还要禁止本地中断。

论坛徽章:
0
8 [报告]
发表于 2010-06-04 22:08 |只看该作者
自旋锁与信号量的不同
1.自旋锁在申请锁失败后,不断忙循环等待锁可用
2.信号量在申请失败后,把自己放到等待队列,然后睡眠。

所以,自旋锁可以用在ISR中,而ISR中不可以使用信号量。

论坛徽章:
0
9 [报告]
发表于 2010-06-04 22:16 |只看该作者
3.如果进程A在内核态下拥有自旋锁,被阻塞后,被调度的另外一个进程B也执行到同样的一段内核代码,申请自旋锁,但是由于进程A并没有释放该锁,所以B会一直自旋等待,同时内核被禁止抢占,也就是说进程B会一直自旋,不会让出处理器。
刚又看了下书,书上说是:如果不支持内核抢占,内核代码就一直执行,知道完成为止。
所以。。。俺也懵了,不懂。

论坛徽章:
0
10 [报告]
发表于 2010-06-04 22:36 |只看该作者
关于内核抢占,Robert Love在LKD原文中是这么写的:

Kernel Preemption
The Linux kernel, unlike most other Unix variants and many other operating systems, is a fully preemptive kernel. In non-preemptive kernels, kernel code runs until completion. That is, the scheduler is not capable of rescheduling a task while it is in the kernelkernel code is scheduled cooperatively, not preemptively. Kernel code runs until it finishes (returns to user-space) or explicitly blocks. In the 2.6 kernel, however, the Linux kernel became preemptive: It is now possible to preempt a task at any point, so long as the kernel is in a state in which it is safe to reschedule.
So when is it safe to reschedule? The kernel is capable of preempting a task running in the kernel so long as it does not hold a lock. That is, locks are used as markers of regions of non-preemptibility. Because the kernel is SMP-safe, if a lock is not held, the current code is reentrant and capable of being preempted.
The first change in supporting kernel preemption was the addition of a preemption counter, preempt_count, to each process's thread_info. This counter begins at zero and increments once for each lock that is acquired and decrements once for each lock that is released. When the counter is zero, the kernel is preemptible. Upon return from interrupt, if returning to kernel-space, the kernel checks the values of need_resched and preempt_count. If need_resched is set and preempt_count is zero, then a more important task is runnable and it is safe to preempt. Thus, the scheduler is invoked. If preempt_count is nonzero, a lock is held and it is unsafe to reschedule. In that case, the interrupt returns as usual to the currently executing task. When all the locks that the current task is holding are released, preempt_count returns to zero. At that time, the unlock code checks whether need_resched is set. If so, the scheduler is invoked. Enabling and disabling kernel preemption is sometimes required in kernel code and is discussed in Chapter 9.
Kernel preemption can also occur explicitly, when a task in the kernel blocks or explicitly calls schedule(). This form of kernel preemption has always been supported because no additional logic is required to ensure that the kernel is in a state that is safe to preempt. It is assumed that the code that explicitly calls schedule() knows it is safe to reschedule.
Kernel preemption can occur
When an interrupt handler exits, before returning to kernel-space
When kernel code becomes preemptible again
If a task in the kernel explicitly calls schedule()
If a task in the kernel blocks (which results in a call to schedule())
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP