2.6.24的内核是可抢占的吗?(已解决)

发布于 2022-09-22 11:31:54 字数 213 浏览 20 评论 0

我让一个进程获得了自旋锁,然后执行schedule_timeout休眠10s(只是测试),之后再释放自旋锁;接着另外一个进程又想获得这个自旋锁,接着就死机了.如果内核是随处都可以抢占的话,是不应该死机的.

请教高手,不是说2.6的内核已经可以抢占了,是不是我用的内核版本编译的不对?

[ 本帖最后由 ryancat 于 2008-9-27 11:00 编辑 ]

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

千仐 2022-09-29 11:31:54

单处理器上,自旋锁不能用在中断,睡眠中

说谎友 2022-09-29 11:31:54

原帖由 eveson 于 2008-9-26 20:49 发表
单处理器上,自旋锁不能用在中断,睡眠中

是的,我这里是做个测试,看内核是否随处都可以抢占.
对这样的结果还是不能理解,如果真的是可抢占内核的话.

倾听心声的旋律 2022-09-29 11:31:54

对于标题,回答是肯定的
对于你说的内容,我觉得你对自旋锁没理解。自旋锁本身就用来禁止抢占的。你在临界区(获得自旋锁的代码区)内睡眠,又没中断打断,不死才怪

不气馁 2022-09-29 11:31:54

原帖由 sep 于 2008-9-26 23:24 发表
对于标题,回答是肯定的
对于你说的内容,我觉得你对自旋锁没理解。自旋锁本身就用来禁止抢占的。你在临界区(获得自旋锁的代码区)内睡眠,又没中断打断,不死才怪

有道理!

愿与i 2022-09-29 11:31:54

原帖由 sep 于 2008-9-26 23:24 发表
对于标题,回答是肯定的
对于你说的内容,我觉得你对自旋锁没理解。自旋锁本身就用来禁止抢占的。你在临界区(获得自旋锁的代码区)内睡眠,又没中断打断,不死才怪

是这样的,我知道获得了自旋锁后不能休眠,但是我这里这样写的目的是验证内核是否可以抢占,这段代码的流程是这样的:
1. 获得自旋锁
2. 休眠10s并调度
3. 释放自旋锁
当只有一个进程执行这段代码的时候,是不会死机的,从调试信息看,10s后确实释放了自旋锁.
但是当一个进程执行了这段代码,然后我又新启一个进程执行这段代码的时候,就系统死机了.
我认为,如果内核是随处可抢占,而不是只在某些关键点可以抢占的话,第2个进程当无法获取自旋锁,自旋一段时候后会再次调度前一个进程执行,就释放掉了自旋锁,系统就不会死机.
所以我觉得这个内核不是像真正的实时系统一样是完全可以抢占的.
代码如下:
ssize_t spin_write(struct file *filp, const char __user *buf, size_t count,
                loff_t *f_pos)
{
        struct spin_dev *dev = filp->private_data;
        int delay = 10;

        printk(KERN_EMERG"process %i(%s) call %s\n", current->pid, current->comm, __FUNCTION__);
        spin_lock_irq(&dev->spinlock);
        printk(KERN_EMERG"process %i(%s) get spinlock\n", current->pid, current->comm);
        printk(KERN_EMERG"process %i(%s) begin to wait %i seconds\n", current->pid, current->comm, delay);
        set_current_state(TASK_INTERRUPTIBLE);
        schedule_timeout(delay * HZ);
        spin_unlock_irq(&dev->spinlock);
        printk(KERN_EMERG"process %i(%s) release spinlock\n", current->pid, current->comm);

        return count;
}

[ 本帖最后由 ryancat 于 2008-9-27 10:01 编辑 ]

倚栏听风 2022-09-29 11:31:54

我印象中spin_lock主要是用于多处理器的吧,实际上是一个循环死等吧。以前Linux都是专门编译SMP版本和非SMP版本的,现在许多发行商图省事好像直接发面的是SMP版本的;当然就算是多核,你这种用法还是有可能最终全部挂死的。

我感觉你对内核“可抢占”的理解有问题,任何系统中,不管怎么设计,但终都会有一部分必须是串行执行的,所谓“可抢占”只是这一部分要尽量小而已,Linux内核的可抢占性是指它进入内核态之后许多时候还是可以被抢占的,并不是在内核的任何执行过程中都能被抢占。你见过哪一个实时操作系统可以在任何时候可以被抢占吗?VxWorks有一个kernel state,一旦进入这个状态任何抢占后最终也需要在kernel state执行的操作都会被挂在一个work queue中,最终串行地执行。

悲喜皆因你 2022-09-29 11:31:54

原帖由 Cyberman.Wu 于 2008-9-27 10:17 发表
我印象中spin_lock主要是用于多处理器的吧,实际上是一个循环死等吧。以前Linux都是专门编译SMP版本和非SMP版本的,现在许多发行商图省事好像直接发面的是SMP版本的;当然就算是多核,你这种用法还是有可能最终 ...

我找到可能的原因了,在单核上面获取自旋锁一般就是关调度,这个时候其他进程就没法抢占了,所以死机.

时光与爱终年不遇 2022-09-29 11:31:54

Linux不清楚,不过一般来说CPU总要干点什么的,关调度并不见得就不能切换。

对于单核,由于同一时刻只有一个任务在招待,所以切换的时机也内有两个,一是当前任务通过调用进入内核空间引起主动切换,另一个是外部中断(包含时钟中断)而导致的切换,所以如果一个任务如果持有信号量而切换出去,后面任务还会继续运行,如果它也去获取这个信号量,就会由于获取失败而也切换出去。而对于spin lock,实际上主动是用于多CPU之前互斥的,由于是非常短的操作,通常就用“忙等”了吧。下面是2.6.9内核中i386的实现:

static inline void _raw_spin_lock(spinlock_t *lock)
{
#ifdef CONFIG_DEBUG_SPINLOCK
        if (unlikely(lock->magic != SPINLOCK_MAGIC)) {
                printk("eip: %p\n", __builtin_return_address(0));
                BUG();
        }
#endif
        __asm__ __volatile__(
                spin_lock_string
                :"=m" (lock->lock) : : "memory");
}

#define spin_lock_string \
        "\n1:\t" \
        "lock ; decb %0\n\t" \
        "jns 3f\n" \
        "2:\t" \
        "rep;nop\n\t" \
        "cmpb $0,%0\n\t" \
        "jle 2b\n\t" \
        "jmp 1b\n" \
        "3:\n\t"

从这里可以看出是一个死循环,只到变量恢复为1为止。

如果只是想锁一下如果不行就不做某种操作应该用spin_trylock吧。另外Linux内核中如果不打开SMP开关编译实际上spin_lock是空操作,就不会出现这种情况了;不过现在的发行版本如果不自己重新编译内核都是直接支持SMP的,主要是现在多核的CPU越来越多,而对于普通用户要编译内核也是很麻烦的。

[ 本帖最后由 Cyberman.Wu 于 2008-9-28 11:02 编辑 ]

无人接听 2022-09-29 11:31:54

对的 2.6肯定是可以抢占的
但是自旋锁是不可中断的

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文