Linux进程(六):睡眠与进程0、进程1

Linux进程(六):睡眠与进程0、进程1

深度睡眠/浅睡眠

  在Linux系统中,进程有两种睡眠状态:深度睡眠和浅度睡眠。其中:深度睡眠只能被资源所唤醒,浅度睡眠可以被资源和signal所唤醒。

在这里插入图片描述

​   深度睡眠有时不可避免,例如发生page fault时:在执行某个程序时,若某些代码段还没有进内存,在我们调用到某个函数时,可能会发生缺页中断。此时Linux内核将把这个进程置为深度睡眠。

​   若上述情况不使用深度睡眠,也就是说若在发生page fault后该进程可被signal唤醒,那我们可以设想这样一种情况:在进程发生缺页中断后进入睡眠状态,此时该进程收到某个信号A,于是该进程需要执行信号A的信号处理函数,若该信号处理函数此时也不在内存内,则又将发生缺页中断并进入睡眠态,若此时该进程又收到信号A,那就进程将一直在唤醒->缺页->睡眠这个循环中反复。因此在Linux内核中,深度睡眠不可避免。

​   以下是一段模拟进程在等待资源时进入深度睡眠的代码:

static ssize_t globalfifo_read(struct file *filp, char __user *buf,
                   size_t count, loff_t *ppos)
{
    int ret;
    struct globalfifo_dev *dev = container_of(filp->private_data,
        struct globalfifo_dev, miscdev);

    DECLARE_WAITQUEUE(wait, current);

    mutex_lock(&dev->mutex);
    add_wait_queue(&dev->r_wait, &wait);
    while (dev->current_len == 0) {
        //进入次循环表示暂时没有可读资源,需要等待
        //若设置了非阻塞,则跳出循环
        if (filp->f_flags & O_NONBLOCK) {
            ret = -EAGAIN;
            goto out;
        }
        //将进程的状态置为TASK_INTERUPTIBLE
        //若设置为TASK_UNINTERRUPTIBLE,状态将变为深度睡眠
        __set_current_state(TASK_INTERRUPTIBLE);
        mutex_unlock(&dev->mutex);
		
        //放弃cpu
        schedule();
        //若是被信号唤醒,直接goto跳出循环
        if (signal_pending(current)) {
            ret = -ERESTARTSYS;
            goto out2;
        }
		//若不是被信号唤醒,则执行任务
        mutex_lock(&dev->mutex);
    }

    if (count > dev->current_len)
        count = dev->current_len;

    if (copy_to_user(buf, dev->mem, count)) {
        ret = -EFAULT;
        goto out;
    } else {
        memcpy(dev->mem, dev->mem + count, dev->current_len - count);
        dev->current_len -= count;
        printk(KERN_INFO "read %d bytes(s),current_len:%d\n", count,
               dev->current_len);

        wake_up_interruptible(&dev->w_wait);

        ret = count;
    }
 out:
    mutex_unlock(&dev->mutex);
 out2:
    remove_wait_queue(&dev->r_wait, &wait);
    set_current_state(TASK_RUNNING);
    return ret;
}

进程0和进程1

  在Linux,每一个task_struct都是被父进程创建出来的。那么此处就存在一个问题:Linux系统中的进程数的根init进程是如何被创建出来的呢?

​   init进程也可以被称为Linux中的进程1,它是由Linux中的进程0所创建的。我们可以在/proc中查看Linux中进程1的父进程:

在这里插入图片描述

  可以看到进程1的PPid字段显示的是0。这说明进程1的父进程实际上是Linux系统中的进程0。而进程0是在Linux系统开机启动的过程中所创建的进程。

  但是我们在pstree中看不到Linux的进程0(注意,init进程为进程1),因为进程0在创建进程1之后就退化成了Linux系统中的IDLE进程。IDLE进程是Linux系统中的一个特殊调度类:当所有的进程都睡眠或停止时,CPU才会调用IDLE进程,同时CPU将被切换为低功耗模式。所以当进程0被调度时,CPU将会被置为Wait For Interrupter或者更深的睡眠状态。在Wait For Interrupter状态中时,CPU只有在接收到一个中断才会被唤醒,否则运行功耗十分低,并且一旦产生一个中断,就可能会唤醒另一个进程。

  这种设计的好处之一在于有效避免了在进程睡眠或等待时的判断,使得每个进程在进入睡眠状态之前不需要考虑自己是否是最后一个可调度的进程而把CPU置为WFI状态。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值